Skip to content
2 changes: 1 addition & 1 deletion include/swift/Basic/FrozenMultiMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class FrozenMultiMap {
// Since our array is sorted, we need to first find the first pair with our
// inst as the first element.
auto start = std::lower_bound(
storage.begin(), storage.end(), std::make_pair(key, Value()),
storage.begin(), storage.end(), std::make_pair(key, llvm::None),
[&](const std::pair<Key, Optional<Value>> &p1,
const std::pair<Key, Optional<Value>> &p2) {
return p1.first < p2.first;
Expand Down
219 changes: 160 additions & 59 deletions include/swift/SIL/FieldSensitivePrunedLiveness.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,16 @@ struct TypeTreeLeafTypeRange {
return TypeTreeLeafTypeRange(start, end);
}

/// Whether \p bits contains any of the in-range bits.
bool intersects(SmallBitVector const &bits) const {
for (auto element : getRange()) {
if (bits.test(element)) {
return true;
}
}
return false;
}

/// Is the given leaf type specified by \p singleLeafElementNumber apart of
/// our \p range of leaf type values in the our larger type.
bool contains(SubElementOffset singleLeafElementNumber) const {
Expand All @@ -358,6 +368,13 @@ struct TypeTreeLeafTypeRange {
endEltOffset >= range.endEltOffset;
}

/// Sets each bit in \p bits corresponding to an element of this range.
void setBits(SmallBitVector &bits) const {
for (auto element : getRange()) {
bits.set(element);
}
}

IntRange<unsigned> getRange() const {
return range(startEltOffset, endEltOffset);
}
Expand Down Expand Up @@ -666,17 +683,68 @@ class FieldSensitivePrunedLiveness {
FieldSensitivePrunedLiveBlocks liveBlocks;

public:
enum IsInterestingUser { NonUser, NonLifetimeEndingUse, LifetimeEndingUse };

struct InterestingUser {
TypeTreeLeafTypeRange subEltSpan;
bool isConsuming;
SmallBitVector liveBits;
SmallBitVector consumingBits;

InterestingUser(unsigned bitCount)
: liveBits(bitCount), consumingBits(bitCount) {}

InterestingUser(unsigned bitCount, TypeTreeLeafTypeRange range,
bool lifetimeEnding)
: liveBits(bitCount), consumingBits(bitCount) {
addUses(range, lifetimeEnding);
}

/// Record that the instruction uses the bits of the value in \p range.
void addUses(TypeTreeLeafTypeRange range, bool lifetimeEnding) {
range.setBits(liveBits);
if (lifetimeEnding) {
range.setBits(consumingBits);
}
}

/// Record that the instruction uses the bits in \p bits.
void addUses(SmallBitVector const &bits, bool lifetimeEnding) {
liveBits |= bits;
if (lifetimeEnding) {
consumingBits |= bits;
}
}

InterestingUser() : subEltSpan(), isConsuming(false) {}
InterestingUser(TypeTreeLeafTypeRange subEltSpan, bool isConsuming)
: subEltSpan(subEltSpan), isConsuming(isConsuming) {}
/// Populates the provided vector with contiguous ranges of bits which are
/// users of the same sort.
void getContiguousRanges(
SmallVectorImpl<std::pair<TypeTreeLeafTypeRange, IsInterestingUser>>
&ranges) const {
if (liveBits.size() == 0)
return;

assert(ranges.empty());
Optional<std::pair<unsigned, IsInterestingUser>> current = llvm::None;
for (unsigned bit = 0, size = liveBits.size(); bit < size; ++bit) {
auto interesting = isInterestingUser(bit);
if (!current) {
current = {bit, interesting};
continue;
}
if (current->second != interesting) {
ranges.push_back(
{TypeTreeLeafTypeRange(current->first, bit), current->second});
current = {bit, interesting};
}
}
ranges.push_back({TypeTreeLeafTypeRange(current->first, liveBits.size()),
current->second});
}

InterestingUser &operator&=(bool otherValue) {
isConsuming &= otherValue;
return *this;
IsInterestingUser isInterestingUser(unsigned element) const {
if (!liveBits.test(element))
return NonUser;
return consumingBits.test(element) ? LifetimeEndingUse
: NonLifetimeEndingUse;
}
};

Expand Down Expand Up @@ -758,42 +826,6 @@ class FieldSensitivePrunedLiveness {
return llvm::make_range(users.begin(), users.end());
}

using LifetimeEndingUserRange = OptionalTransformRange<
UserRange,
function_ref<Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>(
const std::pair<SILInstruction *, InterestingUser> &)>>;
LifetimeEndingUserRange getAllLifetimeEndingUses() const {
assert(isInitialized());
function_ref<Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>(
const std::pair<SILInstruction *, InterestingUser> &)>
op;
op = [](const std::pair<SILInstruction *, InterestingUser> &pair)
-> Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>> {
if (pair.second.isConsuming)
return {{pair.first, pair.second.subEltSpan}};
return None;
};
return LifetimeEndingUserRange(getAllUsers(), op);
}

using NonLifetimeEndingUserRange = OptionalTransformRange<
UserRange,
function_ref<Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>(
const std::pair<SILInstruction *, InterestingUser> &)>>;
NonLifetimeEndingUserRange getAllNonLifetimeEndingUses() const {
assert(isInitialized());
function_ref<Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>(
const std::pair<SILInstruction *, InterestingUser> &)>
op;
op = [](const std::pair<SILInstruction *, InterestingUser> &pair)
-> Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>> {
if (!pair.second.isConsuming)
return {{pair.first, pair.second.subEltSpan}};
return None;
};
return NonLifetimeEndingUserRange(getAllUsers(), op);
}

using UserBlockRange = TransformRange<
UserRange, function_ref<SILBasicBlock *(
const std::pair<SILInstruction *, InterestingUser> &)>>;
Expand Down Expand Up @@ -824,6 +856,9 @@ class FieldSensitivePrunedLiveness {
void updateForUse(SILInstruction *user, TypeTreeLeafTypeRange span,
bool lifetimeEnding);

void updateForUse(SILInstruction *user, SmallBitVector const &bits,
bool lifetimeEnding);

void getBlockLiveness(SILBasicBlock *bb, TypeTreeLeafTypeRange span,
SmallVectorImpl<FieldSensitivePrunedLiveBlocks::IsLive>
&resultingFoundLiveness) const {
Expand All @@ -848,19 +883,46 @@ class FieldSensitivePrunedLiveness {
SmallBitVector &liveOutBits,
SmallBitVector &deadBits) const;

enum IsInterestingUser { NonUser, NonLifetimeEndingUse, LifetimeEndingUse };
InterestingUser &getOrCreateInterestingUser(SILInstruction *user) {
auto iter = users.find(user);
if (iter == users.end()) {
iter = users.insert({user, InterestingUser(getNumSubElements())}).first;
}
return *&iter->second;
}

/// If \p user has had uses recored, return a pointer to the InterestingUser
/// where they've been recorded.
InterestingUser const *getInterestingUser(SILInstruction *user) const {
auto iter = users.find(user);
if (iter == users.end())
return nullptr;
return &iter->second;
}

/// Return a result indicating whether the given user was identified as an
/// interesting use of the current def and whether it ends the lifetime.
std::pair<IsInterestingUser, Optional<TypeTreeLeafTypeRange>>
isInterestingUser(SILInstruction *user) const {
/// How \p user uses the field at \p element.
IsInterestingUser isInterestingUser(SILInstruction *user,
unsigned element) const {
assert(isInitialized());
auto useIter = users.find(user);
if (useIter == users.end())
return {NonUser, None};
auto isInteresting =
useIter->second.isConsuming ? LifetimeEndingUse : NonLifetimeEndingUse;
return {isInteresting, useIter->second.subEltSpan};
auto *record = getInterestingUser(user);
if (!record)
return NonUser;
return record->isInterestingUser(element);
}

/// Whether \p user uses the fields in \p range as indicated by \p kind.
bool isInterestingUserOfKind(SILInstruction *user, IsInterestingUser kind,
TypeTreeLeafTypeRange range) const {
auto *record = getInterestingUser(user);
if (!record) {
return kind == IsInterestingUser::NonUser;
}

for (auto element : range.getRange()) {
if (record->isInterestingUser(element) != kind)
return false;
}
return true;
}

unsigned getNumSubElements() const { return liveBlocks.getNumBitsToTrack(); }
Expand All @@ -886,10 +948,12 @@ class FieldSensitivePrunedLiveness {
/// argument must be copied.
void addInterestingUser(SILInstruction *user, TypeTreeLeafTypeRange range,
bool lifetimeEnding) {
auto iterAndSuccess =
users.insert({user, InterestingUser(range, lifetimeEnding)});
if (!iterAndSuccess.second)
iterAndSuccess.first->second &= lifetimeEnding;
getOrCreateInterestingUser(user).addUses(range, lifetimeEnding);
}

void addInterestingUser(SILInstruction *user, SmallBitVector const &bits,
bool lifetimeEnding) {
getOrCreateInterestingUser(user).addUses(bits, lifetimeEnding);
}
};

Expand Down Expand Up @@ -1003,6 +1067,11 @@ class FieldSensitivePrunedLiveRange : public FieldSensitivePrunedLiveness {
void updateForUse(SILInstruction *user, TypeTreeLeafTypeRange span,
bool lifetimeEnding);

/// Customize updateForUse for FieldSensitivePrunedLiveness such that we check
/// that we consider defs as stopping liveness from being propagated up.
void updateForUse(SILInstruction *user, SmallBitVector const &bits,
bool lifetimeEnding);

/// Compute the boundary from the blocks discovered during liveness analysis.
///
/// Precondition: \p liveness.getDiscoveredBlocks() is a valid list of all
Expand Down Expand Up @@ -1074,6 +1143,14 @@ class FieldSensitiveSSAPrunedLiveRange
return inst == defInst.first && defInst.second->contains(bit);
}

bool isDef(SILInstruction *inst, SmallBitVector const &bits) const {
if (inst != defInst.first)
return false;
SmallBitVector defBits(bits.size());
defInst.second->setBits(defBits);
return (defBits & bits) == bits;
}

bool isDef(SILInstruction *inst, TypeTreeLeafTypeRange span) const {
return inst == defInst.first &&
defInst.second->setIntersection(span).has_value();
Expand Down Expand Up @@ -1184,6 +1261,30 @@ class FieldSensitiveMultiDefPrunedLiveRange
*iter, [&](TypeTreeLeafTypeRange span) { return span.contains(bit); });
}

bool isDef(SILValue value, SmallBitVector const &bits) const {
assert(isInitialized());
auto iter = defs.find(cast<SILNode>(value));
if (!iter)
return false;
SmallBitVector allBits(bits.size());
for (auto range : *iter) {
range.setBits(allBits);
}
return (bits & allBits) == bits;
}

bool isDef(SILInstruction *inst, SmallBitVector const &bits) const {
assert(isInitialized());
auto iter = defs.find(cast<SILNode>(inst));
if (!iter)
return false;
SmallBitVector allBits(bits.size());
for (auto range : *iter) {
range.setBits(allBits);
}
return (bits & allBits) == bits;
}

bool isDef(SILInstruction *inst, TypeTreeLeafTypeRange span) const {
assert(isInitialized());
auto iter = defs.find(cast<SILNode>(inst));
Expand Down
Loading