Skip to content

Tweak FSO explosion heuristics #16756

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

Closed
wants to merge 12 commits into from
Closed
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
49 changes: 49 additions & 0 deletions include/swift/SIL/InstructionUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,55 @@ struct LLVM_LIBRARY_VISIBILITY FindClosureResult {
/// by a reabstraction thunk.
FindClosureResult findClosureForAppliedArg(SILValue V);

struct LLVM_LIBRARY_VISIBILITY FindLocalApplySitesResult {
/// Set to true if the function-ref_ref escapes into a use that our analysis
/// does not understand. Set to false if we found a use that had an actual
/// escape. Set to None if we did not find any call sites, but also didn't
/// find any "escaping uses" as well.
///
/// The none case is so that we can distinguish in between saying that a value
/// did escape and saying that we did not find any conservative information.
Optional<bool> escapes;

/// Contains the list of local non fully applied partial apply sites that we
/// found.
SmallVector<ApplySite, 1> partialApplySites;

/// Contains the list of full apply sites that we found.
SmallVector<FullApplySite, 1> fullApplySites;

/// Deleted default constructor. This is a move only type.
FindLocalApplySitesResult()
: escapes(), partialApplySites(), fullApplySites() {}
FindLocalApplySitesResult(const FindLocalApplySitesResult &) = delete;
FindLocalApplySitesResult(FindLocalApplySitesResult &&) = default;
~FindLocalApplySitesResult() = default;

/// Treat this function ref as escaping if we either found an actual user we
/// didn't understand.
///
/// When determining if we have an "interesting" result, we want to return
/// true if escaping is true or false. That is because conservatively we want
/// to know that we found some sort of information. On the other hand, for
/// determining if non-conservatively we actually did escape, we do not want
/// to consider not finding a value for escaping as equivalent to having an
/// escape.
bool isEscaping() const { return escapes.getValueOr(false); }

/// We convert to true if we have any "non"-conservative information about the
/// FunctionRefInst that was processed.
///
/// NOTE: We want to return true if escapes has any value. Otherwise, we may
/// ignore e
operator bool() const {
return escapes.hasValue() || partialApplySites.size() ||
fullApplySites.size();
}
};

/// Returns true if we found any apply sites for the given function_ref.
FindLocalApplySitesResult findLocalApplySites(FunctionRefInst *FRI);

/// A utility class for evaluating whether a newly parsed or deserialized
/// function has qualified or unqualified ownership.
///
Expand Down
37 changes: 30 additions & 7 deletions include/swift/SIL/Projection.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@
#ifndef SWIFT_SIL_PROJECTION_H
#define SWIFT_SIL_PROJECTION_H

#include "swift/AST/TypeAlignments.h"
#include "swift/Basic/NullablePtr.h"
#include "swift/Basic/PointerIntEnum.h"
#include "swift/AST/TypeAlignments.h"
#include "swift/SIL/SILValue.h"
#include "swift/Basic/STLExtras.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILValue.h"
#include "swift/SILOptimizer/Analysis/ARCAnalysis.h"
#include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h"
#include "llvm/ADT/Hashing.h"
Expand Down Expand Up @@ -766,13 +767,15 @@ class ProjectionTreeNode {
~ProjectionTreeNode() = default;
ProjectionTreeNode(const ProjectionTreeNode &) = default;

llvm::ArrayRef<unsigned> getChildProjections() {
return llvm::makeArrayRef(ChildProjections);
bool isLeaf() const { return ChildProjections.empty(); }

ArrayRef<unsigned> getChildProjections() const {
return llvm::makeArrayRef(ChildProjections);
}

llvm::Optional<Projection> &getProjection() { return Proj; }
Optional<Projection> &getProjection() { return Proj; }

llvm::SmallVector<Operand *, 4> getNonProjUsers() const {
const SmallVectorImpl<Operand *> &getNonProjUsers() const {
return NonProjUsers;
};

Expand Down Expand Up @@ -929,6 +932,24 @@ class ProjectionTree {
return false;
}

void getAllLeafTypes(llvm::SmallVectorImpl<SILType> &outArray) const {
llvm::SmallVector<const ProjectionTreeNode *, 32> worklist;
worklist.push_back(getRoot());

while (!worklist.empty()) {
auto *node = worklist.pop_back_val();
// If we have a leaf node, add its type.
if (node->isLeaf()) {
outArray.push_back(node->getType());
continue;
}

// Otherwise, add the nodes children to the worklist.
transform(node->getChildProjections(), std::back_inserter(worklist),
[&](unsigned idx) { return getNode(idx); });
}
}

void getLiveLeafTypes(llvm::SmallVectorImpl<SILType> &OutArray) const {
for (unsigned LeafIndex : LiveLeafIndices) {
const ProjectionTreeNode *Node = getNode(LeafIndex);
Expand All @@ -955,7 +976,9 @@ class ProjectionTree {
void
replaceValueUsesWithLeafUses(SILBuilder &B, SILLocation Loc,
llvm::SmallVectorImpl<SILValue> &Leafs);


void getUsers(SmallPtrSetImpl<SILInstruction *> &users) const;

private:
void createRoot(SILType BaseTy) {
assert(ProjectionTreeNodes.empty() &&
Expand Down
13 changes: 12 additions & 1 deletion include/swift/SILOptimizer/Analysis/ARCAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ class ConsumedArgToEpilogueReleaseMatcher {
auto iter = ArgInstMap.find(arg);
if (iter == ArgInstMap.end())
return false;
return iter->second.foundSomeButNotAllReleases();
return iter->second.getPartiallyPostDomReleases().hasValue();
}

bool isSingleRelease(SILArgument *arg) const {
Expand Down Expand Up @@ -334,6 +334,17 @@ class ConsumedArgToEpilogueReleaseMatcher {
return completeList.getValue();
}

Optional<ArrayRef<SILInstruction *>>
getPartiallyPostDomReleaseSet(SILArgument *arg) const {
auto iter = ArgInstMap.find(arg);
if (iter == ArgInstMap.end())
return None;
auto partialList = iter->second.getPartiallyPostDomReleases();
if (!partialList)
return None;
return partialList;
}

ArrayRef<SILInstruction *> getReleasesForArgument(SILValue value) const {
auto *arg = dyn_cast<SILArgument>(value);
if (!arg)
Expand Down
Loading