Skip to content

5.9: [MoveOnlyAddressChecker] Fix representation for used fields. #66738

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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