Skip to main content

Python/compile.c (part 6)

Source:

cpython 3.14 @ ab2d84fe1023/Python/compile.c

This annotation covers the post-AST optimizer passes. See python_compile5_detail for comprehension, match, and exception table compilation.

Map

LinesSymbolRole
1-100Basic block constructionSplit instruction stream at jumps and labels
101-220Dead code eliminationRemove unreachable blocks after RETURN/RAISE
221-360Constant folding in CFGLOAD_CONST 1 + LOAD_CONST 2 + BINARY_OP + -> LOAD_CONST 3
361-480Jump threadingReplace jump-to-jump with direct target
481-600Stack depth computationCompute co_stacksize from the flow graph

Reading

Basic block construction

// CPython: Python/compile.c:7180 optimize_basic_block
/* A basic block is a maximal sequence of instructions with:
- No branch instructions except at the end
- No branch targets except at the beginning
Jumps between blocks create the control flow graph (CFG). */
static int
optimize_basic_block(PyCompilerObject *c, basicblock *bb, PyObject *consts)
{
struct instr *target;
for (int i = 0; i < bb->b_iused; i++) {
struct instr *inst = &bb->b_instr[i];
int opcode = inst->i_opcode;
...
}
}

The compiler first creates a flat instruction sequence, then splits it into basic blocks at every jump and label. This enables dataflow analysis and optimization.

Dead code elimination

// CPython: Python/compile.c:7380 mark_reachable
static int
mark_reachable(basicblock *entryblock)
{
/* BFS from the entry block; mark all reachable blocks. */
basicblock **stack = ...;
while (sp > stack) {
basicblock *b = *--sp;
if (b->b_reachable) continue;
b->b_reachable = 1;
if (b->b_next && !b->b_next->b_reachable)
*sp++ = b->b_next;
/* Push jump targets */
for each instruction i in b:
if IS_JUMP(i): push(i.target);
}
return 0;
}

def f(): return 1; return 2 — the second return is in an unreachable block and is eliminated. Dead code elimination runs before exception table generation to avoid emitting handlers for code that will never execute.

Jump threading

// CPython: Python/compile.c:7480 jump_thread
static int
jump_thread(struct instr *inst, struct instr *target, int op)
{
/* If target is also an unconditional jump, skip the middle.
JUMP A -> JUMP B -> ... becomes JUMP B -> ... */
assert(!IS_LABEL(inst->i_opcode));
assert(IS_UNCONDITIONAL_JUMP(target->i_opcode));
if (inst->i_target == target->i_target) return 0; /* Already threaded */
inst->i_target = target->i_target;
return 1;
}

Jump threading eliminates intermediate jump blocks generated by if/else chains and loop constructs. A JUMP_FORWARD that jumps to another JUMP_FORWARD is replaced by a direct jump to the final target.

gopy notes

Basic block construction is compile.BuildFlowGraph in compile/flowgraph.go. Dead code elimination is compile.MarkReachable. Jump threading is compile.ThreadJumps. Stack depth computation is compile.ComputeStackDepth in compile/flowgraph_stackdepth.go.