[wip] DFA based func call optimizations #13750
Draft
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The func call optimization pass updates the
INIT_FCALL
,SEND_
, andDO_FCALL
opcodes to specialized variants when the function is known. In particular, there are variants of theSEND_
operands that never pass by ref, which I assume improves the effectiveness of later passes. It also removes CHECK_FUNC ops and performs inlining.Similarly, the call graph optimization builds a graph of known callers/callees that other passes can use.
@kocsismate noticed that method calls were ignored by these passes unless op1 is
$this
, because the type of op1 is only known after these passes.This PR attempts to improve that by updating the call graph during type inference, and by running the func call optimization pass again after that:
The third point requires to run type inference before zend_mark_cv_references, otherwise we may narrow types, so we run zend_infer_types twice: Once for its effect on callees, and a second time after the func call optimization.
The DFA needs to admit a dependency between the INIT_METHOD_CALL op1_use and the related SEND and DO_FCALL ops. Currently the SSA can not represent this: I've tried adding a fake operand to SEND and DO_FCALL ops, or adding fake use/defs; but I wasn't happy with either, so instead I've added a special case in add_usages().
Unfortunately the effectiveness of these changes is limited by the fact that we must ignore classes declared in other compilation units, and usually there is only one class per file. Here is a comparison of the number of SEND opcodes emitted when executing the symfony demo before and after this change:
Benchmarks also show no noticeable improvement, so I don't plan on attempting to merge this as-is, but this may benefit other optimizations (or benefit from them) in the future.