@@ -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 ;
@@ -940,7 +941,10 @@ label_exception_targets(basicblock *entryblock) {
940
941
/***** CFG optimizations *****/
941
942
942
943
static int
943
- mark_reachable (basicblock * entryblock ) {
944
+ remove_unreachable (basicblock * entryblock ) {
945
+ for (basicblock * b = entryblock ; b != NULL ; b = b -> b_next ) {
946
+ b -> b_predecessors = 0 ;
947
+ }
944
948
basicblock * * stack = make_cfg_traversal_stack (entryblock );
945
949
if (stack == NULL ) {
946
950
return ERROR ;
@@ -972,6 +976,14 @@ mark_reachable(basicblock *entryblock) {
972
976
}
973
977
}
974
978
PyMem_Free (stack );
979
+
980
+ /* Delete unreachable instructions */
981
+ for (basicblock * b = entryblock ; b != NULL ; b = b -> b_next ) {
982
+ if (b -> b_predecessors == 0 ) {
983
+ b -> b_iused = 0 ;
984
+ b -> b_except_handler = 0 ;
985
+ }
986
+ }
975
987
return SUCCESS ;
976
988
}
977
989
@@ -1149,13 +1161,15 @@ jump_thread(cfg_instr *inst, cfg_instr *target, int opcode)
1149
1161
assert (is_jump (target ));
1150
1162
// bpo-45773: If inst->i_target == target->i_target, then nothing actually
1151
1163
// changes (and we fall into an infinite loop):
1164
+ if (inst -> i_loc .lineno == -1 ) assert (inst -> i_loc_propagated );
1165
+ if (target -> i_loc .lineno == -1 ) assert (target -> i_loc_propagated );
1152
1166
if ((inst -> i_loc .lineno == target -> i_loc .lineno ||
1153
- inst -> i_loc . lineno == -1 || target -> i_loc . lineno == -1 ) &&
1167
+ inst -> i_loc_propagated || target -> i_loc_propagated ) &&
1154
1168
inst -> i_target != target -> i_target )
1155
1169
{
1156
1170
inst -> i_target = target -> i_target ;
1157
1171
inst -> i_opcode = opcode ;
1158
- if (inst -> i_loc . lineno == -1 ) {
1172
+ if (inst -> i_loc_propagated && ! target -> i_loc_propagated ) {
1159
1173
inst -> i_loc = target -> i_loc ;
1160
1174
}
1161
1175
return true;
@@ -1714,6 +1728,7 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
1714
1728
return ERROR ;
1715
1729
}
1716
1730
1731
+ static int resolve_line_numbers (cfg_builder * g , int firstlineno );
1717
1732
1718
1733
/* Perform optimizations on a control flow graph.
1719
1734
The consts object should still be in list form to allow new constants
@@ -1723,41 +1738,31 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
1723
1738
NOPs. Later those NOPs are removed.
1724
1739
*/
1725
1740
static int
1726
- optimize_cfg (cfg_builder * g , PyObject * consts , PyObject * const_cache )
1741
+ optimize_cfg (cfg_builder * g , PyObject * consts , PyObject * const_cache , int firstlineno )
1727
1742
{
1728
1743
assert (PyDict_CheckExact (const_cache ));
1729
1744
RETURN_IF_ERROR (check_cfg (g ));
1730
1745
for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
1731
1746
RETURN_IF_ERROR (inline_small_exit_blocks (b ));
1732
1747
}
1748
+ RETURN_IF_ERROR (remove_unreachable (g -> g_entryblock ));
1749
+ RETURN_IF_ERROR (resolve_line_numbers (g , firstlineno ));
1733
1750
for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
1734
1751
RETURN_IF_ERROR (optimize_basic_block (const_cache , b , consts ));
1735
- assert (b -> b_predecessors == 0 );
1736
1752
}
1737
1753
RETURN_IF_ERROR (remove_redundant_nops_and_pairs (g -> g_entryblock ));
1738
1754
for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
1739
1755
RETURN_IF_ERROR (inline_small_exit_blocks (b ));
1740
1756
}
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 ));
1757
+ RETURN_IF_ERROR (remove_unreachable (g -> g_entryblock ));
1754
1758
1755
- for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
1756
- remove_redundant_nops (b );
1759
+ for (int n = 0 ; n < 2 ; n ++ ) {
1760
+ for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
1761
+ remove_redundant_nops (b );
1762
+ }
1763
+ RETURN_IF_ERROR (remove_redundant_jumps (g ));
1757
1764
}
1758
1765
1759
- RETURN_IF_ERROR (remove_redundant_jumps (g ));
1760
-
1761
1766
assert (no_redundant_jumps (g ));
1762
1767
return SUCCESS ;
1763
1768
}
@@ -2174,7 +2179,9 @@ push_cold_blocks_to_end(cfg_builder *g) {
2174
2179
if (!IS_LABEL (b -> b_next -> b_label )) {
2175
2180
b -> b_next -> b_label .id = next_lbl ++ ;
2176
2181
}
2177
- basicblock_addop (explicit_jump , JUMP_NO_INTERRUPT , b -> b_next -> b_label .id , NO_LOCATION );
2182
+ cfg_instr * prev_instr = basicblock_last_instr (b );
2183
+ basicblock_addop (explicit_jump , JUMP_NO_INTERRUPT , b -> b_next -> b_label .id ,
2184
+ prev_instr -> i_loc );
2178
2185
explicit_jump -> b_cold = 1 ;
2179
2186
explicit_jump -> b_next = b -> b_next ;
2180
2187
b -> b_next = explicit_jump ;
@@ -2345,6 +2352,7 @@ propagate_line_numbers(basicblock *entryblock) {
2345
2352
for (int i = 0 ; i < b -> b_iused ; i ++ ) {
2346
2353
if (b -> b_instr [i ].i_loc .lineno < 0 ) {
2347
2354
b -> b_instr [i ].i_loc = prev_location ;
2355
+ b -> b_instr [i ].i_loc_propagated = 1 ;
2348
2356
}
2349
2357
else {
2350
2358
prev_location = b -> b_instr [i ].i_loc ;
@@ -2354,6 +2362,7 @@ propagate_line_numbers(basicblock *entryblock) {
2354
2362
if (b -> b_next -> b_iused > 0 ) {
2355
2363
if (b -> b_next -> b_instr [0 ].i_loc .lineno < 0 ) {
2356
2364
b -> b_next -> b_instr [0 ].i_loc = prev_location ;
2365
+ b -> b_next -> b_instr [0 ].i_loc_propagated = 1 ;
2357
2366
}
2358
2367
}
2359
2368
}
@@ -2362,6 +2371,7 @@ propagate_line_numbers(basicblock *entryblock) {
2362
2371
if (target -> b_predecessors == 1 ) {
2363
2372
if (target -> b_instr [0 ].i_loc .lineno < 0 ) {
2364
2373
target -> b_instr [0 ].i_loc = prev_location ;
2374
+ target -> b_instr [0 ].i_loc_propagated = 1 ;
2365
2375
}
2366
2376
}
2367
2377
}
@@ -2401,7 +2411,6 @@ resolve_line_numbers(cfg_builder *g, int firstlineno)
2401
2411
{
2402
2412
RETURN_IF_ERROR (duplicate_exits_without_lineno (g ));
2403
2413
propagate_line_numbers (g -> g_entryblock );
2404
- guarantee_lineno_for_exits (g -> g_entryblock , firstlineno );
2405
2414
return SUCCESS ;
2406
2415
}
2407
2416
@@ -2417,14 +2426,15 @@ _PyCfg_OptimizeCodeUnit(cfg_builder *g, PyObject *consts, PyObject *const_cache,
2417
2426
RETURN_IF_ERROR (label_exception_targets (g -> g_entryblock ));
2418
2427
2419
2428
/** Optimization **/
2420
- RETURN_IF_ERROR (optimize_cfg (g , consts , const_cache ));
2429
+ RETURN_IF_ERROR (optimize_cfg (g , consts , const_cache , firstlineno ));
2421
2430
RETURN_IF_ERROR (remove_unused_consts (g -> g_entryblock , consts ));
2422
2431
RETURN_IF_ERROR (
2423
2432
add_checks_for_loads_of_uninitialized_variables (
2424
2433
g -> g_entryblock , nlocals , nparams ));
2425
2434
insert_superinstructions (g );
2426
2435
2427
2436
RETURN_IF_ERROR (push_cold_blocks_to_end (g ));
2437
+ guarantee_lineno_for_exits (g -> g_entryblock , firstlineno );
2428
2438
RETURN_IF_ERROR (resolve_line_numbers (g , firstlineno ));
2429
2439
return SUCCESS ;
2430
2440
}
0 commit comments