-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Dataflow: update fieldFlowBranchLimit semantics #15599
Dataflow: update fieldFlowBranchLimit semantics #15599
Conversation
0844619
to
912c8fa
Compare
15a07b2
to
26c3de5
Compare
26c3de5
to
a6419dc
Compare
bdfd86b
to
3abae04
Compare
db93e59
to
3a7d795
Compare
0adaa99
to
d6338b9
Compare
…eturn edge condition (block more)
These could be an empty type, but Unit was available and it probably doesn't matter.
d6338b9
to
3c69f8f
Compare
result = n.asInstruction() or | ||
result = n.asOperand().getUse() or | ||
result = n.(SsaPhiNode).getPhiNode().getBasicBlock().getFirstInstruction() or | ||
n.(IndirectInstruction).hasInstructionAndIndirectionIndex(result, _) or |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
n.hasInstructionAndIndirectionIndex(instr, index)
may actually hold for multiple (instr, index)
pairs, so this predicate really should be called getAnInstruction
. Additionally, this seems to miss a case for IndirectOperand
s which I guess means that slightly fewer nodes than expected will have a second-level scope. However, since the shared library handles missing second-level scopes it's probably not a big deal.
The C/C++ team will probably fix this once this PR has been merged 👍 There are some more follow-ups that we want to do, and I'll write these up as an internal C/C++ issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, one question.
private int ctxDispatchFanoutOnReturn(NodeEx out, DataFlowCall ctx) { | ||
exists(DataFlowCall call, DataFlowCallable c | | ||
simpleDispatchFanoutOnReturn(call, out) > 1 and | ||
not Stage1::revFlow(out, false) and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this restriction needed?
simpleDispatchFanoutOnReturn(call, out) > 1 and | ||
not Stage1::revFlow(out, false) and | ||
call.getEnclosingCallable() = c and | ||
returnCallEdge1(c, _, ctx, _) and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we are only considering contexts ctx
that we also return to; why is that? (and I guess that answers my question above).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This ensures that a call-context is always associated with the dispatch fanout at call
. Either this is nested flow-through, in which case the context will be active in the initial flow-in when entering call
, or this is returning flow that didn't come from a parameter in which case the return-call-context will be the thing that reduces the eventual fanout. This does miss the case where we enter the surrounding scope with a call-context and flow-through at call
without returning further, but I think that's ok - for the "MaD model does lambda callback" case this would only be problematic if there were two lambdas being passed in with flow through the first and then entering the second. If we used the dual constraint not fwdFlow(out, false)
to ensure a call-context from a parameter instead, then we'd miss the important case where a source is inside the lambda callback. So to cover this case we'd need a separate range on contexts to count, and I don't think that's worth the effort.
This makes two changes to the fieldFlowBranchLimit interpretation:
For the return edge condition, special care is taken to still follow call edges that are determined by the call context.
All qltests are also updated to use the default fieldFlowBranchLimit instead of an inflated value to better reflect what's actually used in queries.