Skip to content

[erel-matcher] Do not throw away the list of releases if we do not ha… #17367

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 103 additions & 65 deletions include/swift/SILOptimizer/Analysis/ARCAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,47 @@ class ConsumedArgToEpilogueReleaseMatcher {
ExitKind Kind;
ArrayRef<SILArgumentConvention> ArgumentConventions;

using InstListTy = TinyPtrVector<SILInstruction *>;
llvm::SmallMapVector<SILArgument *, InstListTy, 8> ArgInstMap;
class ArgumentState {
/// The list of releases associated with this argument.
TinyPtrVector<SILInstruction *> releases;

/// Set to true if we found some releases but not all for the argument.
llvm::DenseSet<SILArgument *> FoundSomeReleases;
/// If this is set to true, then we know that we were able to find
/// a set of releases.
bool jointPostDominatingReleaseSet;

public:
ArgumentState(ArrayRef<SILInstruction *> releases)
: releases(releases), jointPostDominatingReleaseSet(false) {}

void addRelease(SILInstruction *release) { releases.push_back(release); }
void setHasJointPostDominatingReleaseSet() {
jointPostDominatingReleaseSet = true;
}

bool foundSomeButNotAllReleases() const {
return releases.size() && !jointPostDominatingReleaseSet;
}

/// If we were able to find a set of releases for this argument that joint
/// post-dominate the argument, return our release set.
Optional<ArrayRef<SILInstruction *>> getFullyPostDomReleases() const {
if (releases.empty() || foundSomeButNotAllReleases())
return None;
return {releases};
}

/// If we were able to find a set of releases for this argument, but those
/// releases do not joint post-dominate the argument, return our release
/// set.
///
/// *NOTE* This returns none if we did not find any releases.
Optional<ArrayRef<SILInstruction *>> getPartiallyPostDomReleases() const {
if (releases.empty() || !foundSomeButNotAllReleases())
return None;
return ArrayRef<SILInstruction *>(releases);
}
};
llvm::SmallMapVector<SILArgument *, ArgumentState, 8> ArgInstMap;

/// Eventually this will be used in place of HasBlock.
SILBasicBlock *ProcessedBlock;
Expand All @@ -227,95 +263,97 @@ class ConsumedArgToEpilogueReleaseMatcher {

bool hasBlock() const { return ProcessedBlock != nullptr; }

bool isEpilogueRelease(SILInstruction *I) const {
bool isEpilogueRelease(SILInstruction *i) const {
// This is not a release instruction in the epilogue block.
if (I->getParent() != ProcessedBlock)
if (i->getParent() != ProcessedBlock)
return false;
for (auto &X : ArgInstMap) {
// Either did not find epilogue release or found exploded epilogue
// releases.
if (X.second.size() != 1)
continue;
if (*X.second.begin() == I)
return true;
}
return false;

using PairTy = const std::pair<SILArgument *, ArgumentState>;
return llvm::any_of(ArgInstMap, [&i](PairTy &p) {
auto completeList = p.second.getFullyPostDomReleases();
// If we did not have a complete post dominating release set, then we do
// not want to treat any releases from p as epilogue releases.
if (!completeList)
return false;

// Then make sure that we either found an epilogue release or found
// exploded epilogue releases. We rely on our callers to split up exploded
// parameters.
return completeList->size() == 1 && *completeList->begin() == i;
});
}

/// Return true if we've found some epilogue releases for the argument
/// but not all.
bool hasSomeReleasesForArgument(SILArgument *Arg) {
return FoundSomeReleases.find(Arg) != FoundSomeReleases.end();
bool hasSomeReleasesForArgument(SILArgument *arg) const {
auto iter = ArgInstMap.find(arg);
if (iter == ArgInstMap.end())
return false;
return iter->second.foundSomeButNotAllReleases();
}

bool isSingleRelease(SILArgument *Arg) const {
auto Iter = ArgInstMap.find(Arg);
assert(Iter != ArgInstMap.end() && "Failed to get release list for argument");
return Iter->second.size() == 1;
bool isSingleRelease(SILArgument *arg) const {
auto iter = ArgInstMap.find(arg);
assert(iter != ArgInstMap.end() &&
"Failed to get release list for argument");

// If we do not have a fully post dominating release set bail.
auto completeList = iter->second.getFullyPostDomReleases();
if (!completeList)
return false;

return completeList->size() == 1;
}

SILInstruction *getSingleReleaseForArgument(SILArgument *Arg) {
auto I = ArgInstMap.find(Arg);
if (I == ArgInstMap.end())
SILInstruction *getSingleReleaseForArgument(SILArgument *arg) const {
auto iter = ArgInstMap.find(arg);
if (iter == ArgInstMap.end())
return nullptr;
if (!isSingleRelease(arg))
return nullptr;
if (!isSingleRelease(Arg))
auto completeList = iter->second.getFullyPostDomReleases();
if (!completeList)
return nullptr;
return *I->second.begin();
return *completeList->begin();
}

SILInstruction *getSingleReleaseForArgument(SILValue V) {
auto *Arg = dyn_cast<SILArgument>(V);
if (!Arg)
SILInstruction *getSingleReleaseForArgument(SILValue value) const {
auto *arg = dyn_cast<SILArgument>(value);
if (!arg)
return nullptr;
return getSingleReleaseForArgument(Arg);
return getSingleReleaseForArgument(arg);
}

ArrayRef<SILInstruction *> getReleasesForArgument(SILArgument *Arg) {
auto I = ArgInstMap.find(Arg);
if (I == ArgInstMap.end())
ArrayRef<SILInstruction *> getReleasesForArgument(SILArgument *arg) const {
auto iter = ArgInstMap.find(arg);
if (iter == ArgInstMap.end())
return {};
auto completeList = iter->second.getFullyPostDomReleases();
if (!completeList)
return {};
return I->second;
return completeList.getValue();
}

ArrayRef<SILInstruction *> getReleasesForArgument(SILValue V) {
auto *Arg = dyn_cast<SILArgument>(V);
if (!Arg)
ArrayRef<SILInstruction *> getReleasesForArgument(SILValue value) const {
auto *arg = dyn_cast<SILArgument>(value);
if (!arg)
return {};
return getReleasesForArgument(Arg);
return getReleasesForArgument(arg);
}

/// Recompute the mapping from argument to consumed arg.
void recompute();

bool isSingleReleaseMatchedToArgument(SILInstruction *Inst) {
return count_if(
ArgInstMap,
[&Inst](const std::pair<SILArgument *, ArrayRef<SILInstruction *>> &P)
-> bool {
if (P.second.size() > 1)
return false;
return *P.second.begin() == Inst;
});
bool isSingleReleaseMatchedToArgument(SILInstruction *inst) {
using PairTy = const std::pair<SILArgument *, ArgumentState>;
return count_if(ArgInstMap, [&inst](PairTy &p) {
auto completeList = p.second.getFullyPostDomReleases();
if (!completeList || completeList->size() > 1)
return false;
return *completeList->begin() == inst;
});
}

using iterator = decltype(ArgInstMap)::iterator;
using const_iterator = decltype(ArgInstMap)::const_iterator;
iterator begin() { return ArgInstMap.begin(); }
iterator end() { return ArgInstMap.end(); }
const_iterator begin() const { return ArgInstMap.begin(); }
const_iterator end() const { return ArgInstMap.end(); }

using reverse_iterator = decltype(ArgInstMap)::reverse_iterator;
using const_reverse_iterator = decltype(ArgInstMap)::const_reverse_iterator;
reverse_iterator rbegin() { return ArgInstMap.rbegin(); }
reverse_iterator rend() { return ArgInstMap.rend(); }
const_reverse_iterator rbegin() const { return ArgInstMap.rbegin(); }
const_reverse_iterator rend() const { return ArgInstMap.rend(); }

unsigned size() const { return ArgInstMap.size(); }

iterator_range<iterator> getRange() { return swift::make_range(begin(), end()); }

private:
/// Return true if we have seen releases to part or all of \p Derived in
/// \p Insts.
Expand Down
Loading