Skip to content

Commit

Permalink
Allow tracing through child scopes in FunctionAnalysis
Browse files Browse the repository at this point in the history
Summary:
Allow `FunctionAnalysis` to emit `ResolveScopeInst`s if the scope that
is available at the point of a call is a descendent of the scope we
actually want. This will allow us to trace a function through inner
scopes while retainin the ability to emit direct calls, or inling
without having to emit a `GetClosureScopeInst`.

Reviewed By: avp

Differential Revision: D68187126

fbshipit-source-id: 12a6132e7daf99bfd1423f0144d263bfa108f0e2
  • Loading branch information
neildhar authored and facebook-github-bot committed Feb 13, 2025
1 parent b58e852 commit 0381ccd
Showing 1 changed file with 52 additions and 13 deletions.
65 changes: 52 additions & 13 deletions lib/Optimizer/Scalar/FunctionAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ void analyzeCreateCallable(BaseCreateCallableInst *create) {
Function *F = create->getFunctionCode();
Module *M = F->getParent();
IRBuilder builder(M);
auto *closureVarScope = llvh::dyn_cast<VariableScope>(create->getVarScope());

// The only kind of function which does not expect a made `this` parameter in
// a construct call is a derived class constructor.
Expand All @@ -156,9 +157,14 @@ void analyzeCreateCallable(BaseCreateCallableInst *create) {
/// values.
bool isAlwaysClosure;

/// An instruction that is known to produce the scope of the closure at the
/// point where the closure is used.
Instruction *scope;
/// An instruction that is known to produce the scope of the closure, or one
/// of its descendents at the point where the closure used. May be null if
/// the scope is not known.
Instruction *knownScope;

/// The VariableScope associated with knownScope. May be null iff knownScope
/// is null.
VariableScope *knownVarScope;
};

// List of instructions whose result we know is the same closure created by
Expand All @@ -178,15 +184,20 @@ void analyzeCreateCallable(BaseCreateCallableInst *create) {
IRBuilder::InstructionDestroyer destroyer{};

worklist.push_back(
{create, true, llvh::dyn_cast<Instruction>(create->getScope())});
{create,
true,
llvh::dyn_cast<Instruction>(create->getScope()),
closureVarScope});
while (!worklist.empty()) {
// Instruction whose only possible closure value is the one being analyzed.
Instruction *closureInst = worklist.back().maybeClosure;
// Whether closureInst may have some non-closure value.
bool isAlwaysClosure = worklist.back().isAlwaysClosure;

// Instruction whose result is known to be the scope of the closure.
auto *knownScope = worklist.pop_back_val().scope;
// Scope that is known to be either the scope of the closure or one of its
// descendents.
auto knownScope = worklist.back().knownScope;
auto knownVarScope = worklist.pop_back_val().knownVarScope;

if (!visited.insert(closureInst).second) {
// Already visited.
Expand All @@ -201,7 +212,18 @@ void analyzeCreateCallable(BaseCreateCallableInst *create) {
F->getAttributesRef(M)._allCallsitesKnownInStrictMode = false;
}
if (call->getCallee() == closureInst) {
registerCallsite(call, create, isAlwaysClosure, knownScope);
auto *callScope = knownScope;
// If the scope we have is not the actual scope of the function we are
// calling, then it must be one of its descendents. Emit a
// ResolveScopeInst to obtain the actual scope.
if (knownScope && knownVarScope != closureVarScope) {
auto [startScope, startVarScope] = getResolveScopeStart(
knownScope, knownVarScope, closureVarScope);
builder.setInsertionPoint(call);
callScope = builder.createResolveScopeInst(
closureVarScope, startVarScope, startScope);
}
registerCallsite(call, create, isAlwaysClosure, callScope);
}
continue;
}
Expand Down Expand Up @@ -232,8 +254,20 @@ void analyzeCreateCallable(BaseCreateCallableInst *create) {
// now be unused, but we avoid deleting any instructions in
// FunctionAnalysis since we are iterating over the IR, so it will be
// deleted by DCE.
if (knownScope)
closureUser->replaceAllUsesWith(knownScope);
if (knownScope) {
auto *replacement = knownScope;
// If the scope we have is not the actual scope of the function we are
// are trying to obtain the scope of, then it must be one of its
// descendents. Emit a ResolveScopeInst to obtain the actual scope.
if (knownVarScope != closureVarScope) {
auto [startScope, startVarScope] = getResolveScopeStart(
knownScope, knownVarScope, closureVarScope);
builder.setInsertionPoint(closureUser);
replacement = builder.createResolveScopeInst(
closureVarScope, startVarScope, startScope);
}
closureUser->replaceAllUsesWith(replacement);
}

// Getting the closure scope does not leak the closure.
continue;
Expand Down Expand Up @@ -273,7 +307,8 @@ void analyzeCreateCallable(BaseCreateCallableInst *create) {
->getType()
.canBeObject() &&
"The result UnionNarrowTrusted of closure is not object");
worklist.push_back({closureUser, isAlwaysClosure, knownScope});
worklist.push_back(
{closureUser, isAlwaysClosure, knownScope, knownVarScope});
continue;
}

Expand All @@ -286,7 +321,8 @@ void analyzeCreateCallable(BaseCreateCallableInst *create) {
CC->getCheckedValue()->getType().canBeObject() &&
"closure type is not object");
if (CC->getType().canBeObject()) {
worklist.push_back({closureUser, isAlwaysClosure, knownScope});
worklist.push_back(
{closureUser, isAlwaysClosure, knownScope, knownVarScope});
continue;
}
}
Expand All @@ -297,7 +333,8 @@ void analyzeCreateCallable(BaseCreateCallableInst *create) {
TII->getCheckedValue()->getType().canBeObject() &&
"closure type is not object");
if (TII->getType().canBeObject()) {
worklist.push_back({closureUser, isAlwaysClosure, knownScope});
worklist.push_back(
{closureUser, isAlwaysClosure, knownScope, knownVarScope});
continue;
}
}
Expand Down Expand Up @@ -332,7 +369,9 @@ void analyzeCreateCallable(BaseCreateCallableInst *create) {
worklist.push_back(
{load,
isAlwaysClosure && noOtherValues,
propagateScope ? load->getScope() : nullptr});
propagateScope ? load->getScope() : nullptr,
propagateScope ? load->getLoadVariable()->getParent()
: nullptr});
}
continue;
}
Expand Down

0 comments on commit 0381ccd

Please sign in to comment.