gh-114265: move line number propagation before cfg optimization, remo… · python/cpython@7e49f27 (original) (raw)
`@@ -29,6 +29,7 @@ typedef struct _PyCfgInstruction {
`
29
29
`int i_opcode;
`
30
30
`int i_oparg;
`
31
31
`_PyCompilerSrcLocation i_loc;
`
``
32
`+
unsigned i_loc_propagated : 1; /* location was set by propagate_line_numbers */
`
32
33
`struct _PyCfgBasicblock i_target; / target block (if jump instruction) */
`
33
34
`struct _PyCfgBasicblock i_except; / target block when exception is raised */
`
34
35
`} cfg_instr;
`
`@@ -504,6 +505,21 @@ no_redundant_jumps(cfg_builder *g) {
`
504
505
`return true;
`
505
506
`}
`
506
507
``
``
508
`+
static bool
`
``
509
`+
all_exits_have_lineno(basicblock *entryblock) {
`
``
510
`+
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
`
``
511
`+
for (int i = 0; i < b->b_iused; i++) {
`
``
512
`+
cfg_instr *instr = &b->b_instr[i];
`
``
513
`+
if (instr->i_opcode == RETURN_VALUE) {
`
``
514
`+
if (instr->i_loc.lineno < 0) {
`
``
515
`+
assert(0);
`
``
516
`+
return false;
`
``
517
`+
}
`
``
518
`+
}
`
``
519
`+
}
`
``
520
`+
}
`
``
521
`+
return true;
`
``
522
`+
}
`
507
523
`#endif
`
508
524
``
509
525
`/***** CFG preprocessing (jump targets and exceptions) *****/
`
`@@ -940,7 +956,10 @@ label_exception_targets(basicblock *entryblock) {
`
940
956
`/***** CFG optimizations *****/
`
941
957
``
942
958
`static int
`
943
``
`-
mark_reachable(basicblock *entryblock) {
`
``
959
`+
remove_unreachable(basicblock *entryblock) {
`
``
960
`+
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
`
``
961
`+
b->b_predecessors = 0;
`
``
962
`+
}
`
944
963
`basicblock **stack = make_cfg_traversal_stack(entryblock);
`
945
964
`if (stack == NULL) {
`
946
965
`return ERROR;
`
`@@ -972,6 +991,14 @@ mark_reachable(basicblock *entryblock) {
`
972
991
` }
`
973
992
` }
`
974
993
`PyMem_Free(stack);
`
``
994
+
``
995
`+
/* Delete unreachable instructions */
`
``
996
`+
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
`
``
997
`+
if (b->b_predecessors == 0) {
`
``
998
`+
b->b_iused = 0;
`
``
999
`+
b->b_except_handler = 0;
`
``
1000
`+
}
`
``
1001
`+
}
`
975
1002
`return SUCCESS;
`
976
1003
`}
`
977
1004
``
`@@ -1149,13 +1176,15 @@ jump_thread(cfg_instr *inst, cfg_instr *target, int opcode)
`
1149
1176
`assert(is_jump(target));
`
1150
1177
`// bpo-45773: If inst->i_target == target->i_target, then nothing actually
`
1151
1178
`// changes (and we fall into an infinite loop):
`
``
1179
`+
if (inst->i_loc.lineno == -1) assert(inst->i_loc_propagated);
`
``
1180
`+
if (target->i_loc.lineno == -1) assert(target->i_loc_propagated);
`
1152
1181
`if ((inst->i_loc.lineno == target->i_loc.lineno ||
`
1153
``
`-
inst->i_loc.lineno == -1 || target->i_loc.lineno == -1) &&
`
``
1182
`+
inst->i_loc_propagated || target->i_loc_propagated) &&
`
1154
1183
`inst->i_target != target->i_target)
`
1155
1184
` {
`
1156
1185
`inst->i_target = target->i_target;
`
1157
1186
`inst->i_opcode = opcode;
`
1158
``
`-
if (inst->i_loc.lineno == -1) {
`
``
1187
`+
if (inst->i_loc_propagated && !target->i_loc_propagated) {
`
1159
1188
`inst->i_loc = target->i_loc;
`
1160
1189
` }
`
1161
1190
`return true;
`
`@@ -1714,6 +1743,7 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
`
1714
1743
`return ERROR;
`
1715
1744
`}
`
1716
1745
``
``
1746
`+
static int resolve_line_numbers(cfg_builder *g, int firstlineno);
`
1717
1747
``
1718
1748
`/* Perform optimizations on a control flow graph.
`
1719
1749
` The consts object should still be in list form to allow new constants
`
`@@ -1723,41 +1753,31 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
`
1723
1753
` NOPs. Later those NOPs are removed.
`
1724
1754
`*/
`
1725
1755
`static int
`
1726
``
`-
optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache)
`
``
1756
`+
optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache, int firstlineno)
`
1727
1757
`{
`
1728
1758
`assert(PyDict_CheckExact(const_cache));
`
1729
1759
`RETURN_IF_ERROR(check_cfg(g));
`
1730
1760
`for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
`
1731
1761
`RETURN_IF_ERROR(inline_small_exit_blocks(b));
`
1732
1762
` }
`
``
1763
`+
RETURN_IF_ERROR(remove_unreachable(g->g_entryblock));
`
``
1764
`+
RETURN_IF_ERROR(resolve_line_numbers(g, firstlineno));
`
1733
1765
`for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
`
1734
1766
`RETURN_IF_ERROR(optimize_basic_block(const_cache, b, consts));
`
1735
``
`-
assert(b->b_predecessors == 0);
`
1736
1767
` }
`
1737
1768
`RETURN_IF_ERROR(remove_redundant_nops_and_pairs(g->g_entryblock));
`
1738
1769
`for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
`
1739
1770
`RETURN_IF_ERROR(inline_small_exit_blocks(b));
`
1740
1771
` }
`
1741
``
`-
RETURN_IF_ERROR(mark_reachable(g->g_entryblock));
`
1742
``
-
1743
``
`-
/* Delete unreachable instructions */
`
1744
``
`-
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
`
1745
``
`-
if (b->b_predecessors == 0) {
`
1746
``
`-
b->b_iused = 0;
`
1747
``
`-
b->b_except_handler = 0;
`
1748
``
`-
}
`
1749
``
`-
}
`
1750
``
`-
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
`
1751
``
`-
remove_redundant_nops(b);
`
1752
``
`-
}
`
1753
``
`-
RETURN_IF_ERROR(remove_redundant_jumps(g));
`
``
1772
`+
RETURN_IF_ERROR(remove_unreachable(g->g_entryblock));
`
1754
1773
``
1755
``
`-
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
`
1756
``
`-
remove_redundant_nops(b);
`
``
1774
`+
for (int n = 0; n < 2; n++) {
`
``
1775
`+
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
`
``
1776
`+
remove_redundant_nops(b);
`
``
1777
`+
}
`
``
1778
`+
RETURN_IF_ERROR(remove_redundant_jumps(g));
`
1757
1779
` }
`
1758
1780
``
1759
``
`-
RETURN_IF_ERROR(remove_redundant_jumps(g));
`
1760
``
-
1761
1781
`assert(no_redundant_jumps(g));
`
1762
1782
`return SUCCESS;
`
1763
1783
`}
`
`@@ -2174,7 +2194,13 @@ push_cold_blocks_to_end(cfg_builder *g) {
`
2174
2194
`if (!IS_LABEL(b->b_next->b_label)) {
`
2175
2195
`b->b_next->b_label.id = next_lbl++;
`
2176
2196
` }
`
2177
``
`-
basicblock_addop(explicit_jump, JUMP_NO_INTERRUPT, b->b_next->b_label.id, NO_LOCATION);
`
``
2197
`+
cfg_instr *prev_instr = basicblock_last_instr(b);
`
``
2198
`+
// b cannot be empty because at the end of an exception handler
`
``
2199
`+
// there is always a POP_EXCEPT + RERAISE/RETURN
`
``
2200
`+
assert(prev_instr);
`
``
2201
+
``
2202
`+
basicblock_addop(explicit_jump, JUMP_NO_INTERRUPT, b->b_next->b_label.id,
`
``
2203
`+
prev_instr->i_loc);
`
2178
2204
`explicit_jump->b_cold = 1;
`
2179
2205
`explicit_jump->b_next = b->b_next;
`
2180
2206
`b->b_next = explicit_jump;
`
`@@ -2345,6 +2371,7 @@ propagate_line_numbers(basicblock *entryblock) {
`
2345
2371
`for (int i = 0; i < b->b_iused; i++) {
`
2346
2372
`if (b->b_instr[i].i_loc.lineno < 0) {
`
2347
2373
`b->b_instr[i].i_loc = prev_location;
`
``
2374
`+
b->b_instr[i].i_loc_propagated = 1;
`
2348
2375
` }
`
2349
2376
`else {
`
2350
2377
`prev_location = b->b_instr[i].i_loc;
`
`@@ -2354,6 +2381,7 @@ propagate_line_numbers(basicblock *entryblock) {
`
2354
2381
`if (b->b_next->b_iused > 0) {
`
2355
2382
`if (b->b_next->b_instr[0].i_loc.lineno < 0) {
`
2356
2383
`b->b_next->b_instr[0].i_loc = prev_location;
`
``
2384
`+
b->b_next->b_instr[0].i_loc_propagated = 1;
`
2357
2385
` }
`
2358
2386
` }
`
2359
2387
` }
`
`@@ -2362,46 +2390,18 @@ propagate_line_numbers(basicblock *entryblock) {
`
2362
2390
`if (target->b_predecessors == 1) {
`
2363
2391
`if (target->b_instr[0].i_loc.lineno < 0) {
`
2364
2392
`target->b_instr[0].i_loc = prev_location;
`
``
2393
`+
target->b_instr[0].i_loc_propagated = 1;
`
2365
2394
` }
`
2366
2395
` }
`
2367
2396
` }
`
2368
2397
` }
`
2369
2398
`}
`
2370
2399
``
2371
``
`-
/* Make sure that all returns have a line number, even if early passes
`
2372
``
`-
- have failed to propagate a correct line number.
`
2373
``
`-
- The resulting line number may not be correct according to PEP 626,
`
2374
``
`-
- but should be "good enough", and no worse than in older versions. */
`
2375
``
`-
static void
`
2376
``
`-
guarantee_lineno_for_exits(basicblock *entryblock, int firstlineno) {
`
2377
``
`-
int lineno = firstlineno;
`
2378
``
`-
assert(lineno > 0);
`
2379
``
`-
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
`
2380
``
`-
cfg_instr *last = basicblock_last_instr(b);
`
2381
``
`-
if (last == NULL) {
`
2382
``
`-
continue;
`
2383
``
`-
}
`
2384
``
`-
if (last->i_loc.lineno < 0) {
`
2385
``
`-
if (last->i_opcode == RETURN_VALUE) {
`
2386
``
`-
for (int i = 0; i < b->b_iused; i++) {
`
2387
``
`-
assert(b->b_instr[i].i_loc.lineno < 0);
`
2388
``
-
2389
``
`-
b->b_instr[i].i_loc.lineno = lineno;
`
2390
``
`-
}
`
2391
``
`-
}
`
2392
``
`-
}
`
2393
``
`-
else {
`
2394
``
`-
lineno = last->i_loc.lineno;
`
2395
``
`-
}
`
2396
``
`-
}
`
2397
``
`-
}
`
2398
``
-
2399
2400
`static int
`
2400
2401
`resolve_line_numbers(cfg_builder *g, int firstlineno)
`
2401
2402
`{
`
2402
2403
`RETURN_IF_ERROR(duplicate_exits_without_lineno(g));
`
2403
2404
`propagate_line_numbers(g->g_entryblock);
`
2404
``
`-
guarantee_lineno_for_exits(g->g_entryblock, firstlineno);
`
2405
2405
`return SUCCESS;
`
2406
2406
`}
`
2407
2407
``
`@@ -2417,14 +2417,15 @@ _PyCfg_OptimizeCodeUnit(cfg_builder *g, PyObject *consts, PyObject *const_cache,
`
2417
2417
`RETURN_IF_ERROR(label_exception_targets(g->g_entryblock));
`
2418
2418
``
2419
2419
`/** Optimization **/
`
2420
``
`-
RETURN_IF_ERROR(optimize_cfg(g, consts, const_cache));
`
``
2420
`+
RETURN_IF_ERROR(optimize_cfg(g, consts, const_cache, firstlineno));
`
2421
2421
`RETURN_IF_ERROR(remove_unused_consts(g->g_entryblock, consts));
`
2422
2422
`RETURN_IF_ERROR(
`
2423
2423
`add_checks_for_loads_of_uninitialized_variables(
`
2424
2424
`g->g_entryblock, nlocals, nparams));
`
2425
2425
`insert_superinstructions(g);
`
2426
2426
``
2427
2427
`RETURN_IF_ERROR(push_cold_blocks_to_end(g));
`
``
2428
`+
assert(all_exits_have_lineno(g->g_entryblock));
`
2428
2429
`RETURN_IF_ERROR(resolve_line_numbers(g, firstlineno));
`
2429
2430
`return SUCCESS;
`
2430
2431
`}
`