Compiler improvements #235
Replies: 10 comments 17 replies
-
BPO issue for splitting up compiler: https://bugs.python.org/issue42926 |
Beta Was this translation helpful? Give feedback.
-
Following up on the suggestion on the bpo to change all jumps to be absolute, so that code can be moved around more easily. I looked at the code, and it seems that the jump labels are resolved quite late, so maybe it's fine to leave the relative ones, as long as we do all code reorgs before this. The complexity in this is related to jumps with extended_args (see the "awful hack" comment). I got some stats from the top PYPI packages.
So about 5% of the absolute jumps have extended args. Idea: We add an opcode for them, JUMP_EXTENDED which takes the target from a targets array on the code object, That would simplify assemble_jump_offsets, because the code size won't change in it. In ceval it's the difference between constructing the target from multiple opcodes, vs a table lookup (+ a new opcode). |
Beta Was this translation helpful? Give feedback.
-
It doesn't matter whether absolute or relative. What matters is that any jump can go backwards. |
Beta Was this translation helpful? Give feedback.
-
After implementing the split between codegen and basic block construction, I managed to get multi-exit basicblocks to work with a few changes to the code (remove assertions that jumps are the last instruction in the block, chop off unreachable suffixes of blocks, etc). I then realized that the refactor is not actually necessary for this - I can achieve the same effect in a much simpler way by making NEXT_BLOCK() be a noop, and letting the codegen stage produce the extended basic block directly. (Then we can just remove the NEXT_BLOCK() calls). I don't currently see an advantage to separating codegen from basicblock construction, so I will go with this change for now, and if there is another reason for the refactor we can do it then. |
Beta Was this translation helpful? Give feedback.
-
In my mind there are two advantages to separating code gen from block construction.
[Btw, "superblocks" is the term used in academic literature for blocks with one entry and multiple exits. If a block has more than one exit, it isn't "basic".] |
Beta Was this translation helpful? Give feedback.
-
Can SETUP_FINALLY and friends be replaced with properties of a basic block placed in its beginning, before any instruction? |
Beta Was this translation helpful? Give feedback.
-
It turns out that we can remove NEXT_BLOCK without any other changes - I did this in python/cpython#31448. This will create more empty basic blocks, where there is a jump followed by an explicit block (now it will create an empty implicit block after the jump, and then the explicit block). The empty blocks are discarded in the first step of the code generation, I don't know if it's worth trying to avoid creating them in the first place. I'd probably need to count/measure. If we remove the implicit block creation, then we get superblocks. We need to update the cfg analysis code in a few places, where it assumes that jumps are the last instruction in a block. I have a patch that does this and all tests pass, except a couple of tests that check line numbers / trace output. However, putting aside the line number propagation issue for the moment, I don't think this makes anything simpler - it just makes us loop over the instructions in each block multiple times to find the jumps. It's not currently clear to me what we want to get from a refactor, and what we need at each stage.
|
Beta Was this translation helpful? Give feedback.
-
For reference, this is the branch I mentioned above where NEXT_BLOCK becomes a NOOP and we create superblocks instead of basicblocks (all tests pass except a couple due to incorrect line numbers in the trace). |
Beta Was this translation helpful? Give feedback.
-
I've made #297 to discuss the implementation of jumps. |
Beta Was this translation helpful? Give feedback.
-
In the spirit of not calculating in the front end things that can be easily deduced in the backend, I made a PR to remove Issue python/cpython#93444 |
Beta Was this translation helpful? Give feedback.
-
@markshannon suggested that I look into improving the compiler's implementation.
There are two major objectives/problem areas. One is that the code evolved into a state where it is hard to understand/maintain.
The second problem is that the complexity is probably hurting the quality of the compiler's optimizations.
A few initial points:
The basicblock generation embeds jumps/exception handlers in the code and this complicates the CFG analysis later. We saw this in python/cpython#30544 (comment) where adding an explicit jump that should not have changed anything (because it was to the same target as the implicit jump) created a significant difference in the generated code.
Each basic block can have one exit, so we can store the jump target on the basicblock. Currently there could be more than one exception target, because SETUP_FINALLY et al. can appear in the middle of the block. But if we change this so that those opcodes must be at the beginning (or end?) of a basic block, then we can have the except_target on the basicblock struct as well (the stack of targets will be maintained by the compiler in the code generation stage rather than in the second pass that needs to read the opcodes). The generation of the exception table is simpler, and we no longer need the pass that replaces the virtual opcodes by NOPs (we can emit NOPs to begin with for tracing until that issue is resolved).
Currently all basic blocks are considered equal by the optimizations. If we add a hot/cold field to a basicblock then the optimizer can make better tradeoffs (like not inline code in cold block). basicblocks that belong to an exception handler are an example of a cold block. The hot/cold flag can also be used to decide about code layout - for instance cold blocks can be laid out at the end of the function. Currently code is laid out in the order in which the blocks are created, I believe.
Beta Was this translation helpful? Give feedback.
All reactions