Skip to content

Commit

Permalink
Add MayBindDynamicSelf to CallGraphAnalysis.
Browse files Browse the repository at this point in the history
Why did I choose to pollute the call graph? Because it's convenient,
efficient, and more robust than any current alternative.  This is a
property of the parent function that depends on all the call sites. We
need to cache this information somehow and update it whenever edges
are added to the call graph. The call graph does this perfectly.

The thing I don't like is that it is conservative and may not return a
precise answer after updates, which is generally undesirable. You
normally want to get the same answer whether you update or recompute
an analysis. Although this is generally bad, it is a good tradeoff
now. The need for this call graph property is a consequence of the
current SIL representation which should change soon. It only comes up
in bizarre corner cases, and the imprecision will never show up in
practice.

Swift SVN r28784
  • Loading branch information
atrick committed May 19, 2015
1 parent b8ad66e commit 6f20771
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 6 deletions.
12 changes: 11 additions & 1 deletion include/swift/SILAnalysis/CallGraphAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,17 @@ class CallGraphNode {
/// Do we know all the potential callers of this function?
bool CallerEdgesComplete;

/// May this function bind dynamic Self at one of its call sites? This is
/// conservatively correct because it may stay on after edges are removed.
bool MayBindDynamicSelf;

public:
friend class CallGraph;

CallGraphNode(SILFunction *Function, unsigned Ordinal)
: Function(Function), Ordinal(Ordinal),
CallerEdgesComplete(!canHaveIndirectUses(Function)) {
CallerEdgesComplete(!canHaveIndirectUses(Function)),
MayBindDynamicSelf(false) {
assert(Function &&
"Cannot build a call graph node with a null function pointer!");
}
Expand Down Expand Up @@ -186,6 +191,11 @@ class CallGraphNode {
return CallerEdgesComplete;
}

/// May this function bind dynamic Self at one of its call sites?
bool mayBindDynamicSelf() const {
return MayBindDynamicSelf;
}

/// Is this call graph node for a function that we can trivially
/// know is dead?
bool isDead() const {
Expand Down
4 changes: 4 additions & 0 deletions include/swift/SILPasses/Utils/Local.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ bool hasUnboundGenericTypes(ArrayRef<Substitution> Subs);
/// substitution that refers to the dynamic Self type.
bool hasDynamicSelfTypes(TypeSubstitutionMap &SubsMap);

/// \brief Return true if the substitution list contains a
/// substitution that refers to the dynamic Self type.
bool hasDynamicSelfTypes(ArrayRef<Substitution> Subs);

/// \brief Move an ApplyInst's FuncRef so that it dominates the call site.
void placeFuncRef(ApplyInst *AI, DominanceInfo *DT);

Expand Down
16 changes: 11 additions & 5 deletions lib/SILAnalysis/CallGraphAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//

#include "swift/SILAnalysis/CallGraphAnalysis.h"
#include "swift/SILPasses/Utils/Local.h"
#include "swift/Basic/Fallthrough.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SetVector.h"
Expand Down Expand Up @@ -218,6 +219,8 @@ void CallGraph::addEdgesForApply(FullApplySite AI, CallGraphNode *CallerNode) {
CallGraphEdge::CalleeSetType CalleeSet;
bool Complete = false;

CallerNode->MayBindDynamicSelf |= hasDynamicSelfTypes(AI.getSubstitutions());

if (tryGetCalleeSet(AI.getCallee(), CalleeSet, Complete)) {
auto *Edge = new (Allocator) CallGraphEdge(AI, CalleeSet, Complete,
EdgeOrdinal++);
Expand Down Expand Up @@ -361,11 +364,14 @@ void CallGraphNode::dump() {

llvm::errs() << Ordinal;
if (isDead())
llvm::errs() << " [dead]: ";
else if (isCallerEdgesComplete())
llvm::errs() << " (all callers known): ";
else
llvm::errs() << ": ";
llvm::errs() << " [dead]";
else {
if (isCallerEdgesComplete())
llvm::errs() << " (all callers known)";
if (mayBindDynamicSelf())
llvm::errs() << " (binds Self)";
}
llvm::errs() << ": ";

llvm::errs() << getFunction()->getName() << "\n";
if (Edges.empty())
Expand Down
9 changes: 9 additions & 0 deletions lib/SILPasses/Utils/Local.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,15 @@ bool swift::hasDynamicSelfTypes(TypeSubstitutionMap &SubsMap) {
return false;
}

bool swift::hasDynamicSelfTypes(ArrayRef<Substitution> Subs) {
// Check whether any of the substitutions are refer to dynamic self.
for (auto &sub : Subs)
if (sub.getReplacement()->getCanonicalType()->hasDynamicSelfType())
return true;

return false;
}

/// Find a new position for an ApplyInst's FuncRef so that it dominates its
/// use. Not that FuncionRefInsts may be shared by multiple ApplyInsts.
void swift::placeFuncRef(ApplyInst *AI, DominanceInfo *DT) {
Expand Down

0 comments on commit 6f20771

Please sign in to comment.