@@ -95,7 +95,8 @@ typedef struct basicblock_ {
9595 struct basicblock_ * b_next ;
9696 /* b_return is true if a RETURN_VALUE opcode is inserted. */
9797 unsigned b_return : 1 ;
98- unsigned b_reachable : 1 ;
98+ /* Number of predecssors that a block has. */
99+ int b_predecessors ;
99100 /* Basic block has no fall through (it ends with a return, raise or jump) */
100101 unsigned b_nofallthrough : 1 ;
101102 /* Basic block exits scope (it ends with a return or raise) */
@@ -825,6 +826,7 @@ compiler_copy_block(struct compiler *c, basicblock *block)
825826 result -> b_instr [n ] = block -> b_instr [i ];
826827 }
827828 result -> b_exit = block -> b_exit ;
829+ result -> b_nofallthrough = 1 ;
828830 return result ;
829831}
830832
@@ -1169,7 +1171,7 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
11691171*/
11701172
11711173static int
1172- compiler_addop (struct compiler * c , int opcode )
1174+ compiler_addop_line (struct compiler * c , int opcode , int line )
11731175{
11741176 basicblock * b ;
11751177 struct instr * i ;
@@ -1184,10 +1186,23 @@ compiler_addop(struct compiler *c, int opcode)
11841186 i -> i_oparg = 0 ;
11851187 if (opcode == RETURN_VALUE )
11861188 b -> b_return = 1 ;
1187- i -> i_lineno = c -> u -> u_lineno ;
1189+ i -> i_lineno = line ;
11881190 return 1 ;
11891191}
11901192
1193+ static int
1194+ compiler_addop (struct compiler * c , int opcode )
1195+ {
1196+ return compiler_addop_line (c , opcode , c -> u -> u_lineno );
1197+ }
1198+
1199+ static int
1200+ compiler_addop_noline (struct compiler * c , int opcode )
1201+ {
1202+ return compiler_addop_line (c , opcode , -1 );
1203+ }
1204+
1205+
11911206static Py_ssize_t
11921207compiler_add_o (PyObject * dict , PyObject * o )
11931208{
@@ -1448,6 +1463,11 @@ compiler_addop_j_noline(struct compiler *c, int opcode, basicblock *b)
14481463 return 0; \
14491464}
14501465
1466+ #define ADDOP_NOLINE (C , OP ) { \
1467+ if (!compiler_addop_noline((C), (OP))) \
1468+ return 0; \
1469+ }
1470+
14511471#define ADDOP_IN_SCOPE (C , OP ) { \
14521472 if (!compiler_addop((C), (OP))) { \
14531473 compiler_exit_scope(c); \
@@ -2955,9 +2975,7 @@ compiler_try_finally(struct compiler *c, stmt_ty s)
29552975 else {
29562976 VISIT_SEQ (c , stmt , s -> v .Try .body );
29572977 }
2958- /* Mark code as artificial */
2959- c -> u -> u_lineno = -1 ;
2960- ADDOP (c , POP_BLOCK );
2978+ ADDOP_NOLINE (c , POP_BLOCK );
29612979 compiler_pop_fblock (c , FINALLY_TRY , body );
29622980 VISIT_SEQ (c , stmt , s -> v .Try .finalbody );
29632981 ADDOP_JUMP_NOLINE (c , JUMP_FORWARD , exit );
@@ -3019,9 +3037,9 @@ compiler_try_except(struct compiler *c, stmt_ty s)
30193037 if (!compiler_push_fblock (c , TRY_EXCEPT , body , NULL , NULL ))
30203038 return 0 ;
30213039 VISIT_SEQ (c , stmt , s -> v .Try .body );
3022- ADDOP (c , POP_BLOCK );
30233040 compiler_pop_fblock (c , TRY_EXCEPT , body );
3024- ADDOP_JUMP (c , JUMP_FORWARD , orelse );
3041+ ADDOP_NOLINE (c , POP_BLOCK );
3042+ ADDOP_JUMP_NOLINE (c , JUMP_FORWARD , orelse );
30253043 n = asdl_seq_LEN (s -> v .Try .handlers );
30263044 compiler_use_next_block (c , except );
30273045 /* Runtime will push a block here, so we need to account for that */
@@ -4925,6 +4943,9 @@ compiler_with(struct compiler *c, stmt_ty s, int pos)
49254943 else if (!compiler_with (c , s , pos ))
49264944 return 0 ;
49274945
4946+
4947+ /* Mark all following code as artificial */
4948+ c -> u -> u_lineno = -1 ;
49284949 ADDOP (c , POP_BLOCK );
49294950 compiler_pop_fblock (c , WITH , block );
49304951
@@ -6396,36 +6417,71 @@ mark_reachable(struct assembler *a) {
63966417 if (stack == NULL ) {
63976418 return -1 ;
63986419 }
6399- a -> a_entry -> b_reachable = 1 ;
6420+ a -> a_entry -> b_predecessors = 1 ;
64006421 * sp ++ = a -> a_entry ;
64016422 while (sp > stack ) {
64026423 basicblock * b = * (-- sp );
6403- if (b -> b_next && !b -> b_nofallthrough && b -> b_next -> b_reachable == 0 ) {
6404- b -> b_next -> b_reachable = 1 ;
6405- * sp ++ = b -> b_next ;
6424+ if (b -> b_next && !b -> b_nofallthrough ) {
6425+ if (b -> b_next -> b_predecessors == 0 ) {
6426+ * sp ++ = b -> b_next ;
6427+ }
6428+ b -> b_next -> b_predecessors ++ ;
64066429 }
64076430 for (int i = 0 ; i < b -> b_iused ; i ++ ) {
64086431 basicblock * target ;
64096432 if (is_jump (& b -> b_instr [i ])) {
64106433 target = b -> b_instr [i ].i_target ;
6411- if (target -> b_reachable == 0 ) {
6412- target -> b_reachable = 1 ;
6434+ if (target -> b_predecessors == 0 ) {
64136435 * sp ++ = target ;
64146436 }
6437+ target -> b_predecessors ++ ;
64156438 }
64166439 }
64176440 }
64186441 PyObject_Free (stack );
64196442 return 0 ;
64206443}
64216444
6445+ static void
6446+ eliminate_empty_basic_blocks (basicblock * entry ) {
6447+ /* Eliminate empty blocks */
6448+ for (basicblock * b = entry ; b != NULL ; b = b -> b_next ) {
6449+ basicblock * next = b -> b_next ;
6450+ if (next ) {
6451+ while (next -> b_iused == 0 && next -> b_next ) {
6452+ next = next -> b_next ;
6453+ }
6454+ b -> b_next = next ;
6455+ }
6456+ }
6457+ for (basicblock * b = entry ; b != NULL ; b = b -> b_next ) {
6458+ if (b -> b_iused == 0 ) {
6459+ continue ;
6460+ }
6461+ if (is_jump (& b -> b_instr [b -> b_iused - 1 ])) {
6462+ basicblock * target = b -> b_instr [b -> b_iused - 1 ].i_target ;
6463+ while (target -> b_iused == 0 ) {
6464+ target = target -> b_next ;
6465+ }
6466+ b -> b_instr [b -> b_iused - 1 ].i_target = target ;
6467+ }
6468+ }
6469+ }
6470+
6471+
64226472/* If an instruction has no line number, but it's predecessor in the BB does,
6423- * then copy the line number. This reduces the size of the line number table,
6473+ * then copy the line number. If a successor block has no line number, and only
6474+ * one predecessor, then inherit the line number.
6475+ * This ensures that all exit blocks (with one predecessor) receive a line number.
6476+ * Also reduces the size of the line number table,
64246477 * but has no impact on the generated line number events.
64256478 */
64266479static void
6427- minimize_lineno_table (struct assembler * a ) {
6480+ propogate_line_numbers (struct assembler * a ) {
64286481 for (basicblock * b = a -> a_entry ; b != NULL ; b = b -> b_next ) {
6482+ if (b -> b_iused == 0 ) {
6483+ continue ;
6484+ }
64296485 int prev_lineno = -1 ;
64306486 for (int i = 0 ; i < b -> b_iused ; i ++ ) {
64316487 if (b -> b_instr [i ].i_lineno < 0 ) {
@@ -6435,7 +6491,27 @@ minimize_lineno_table(struct assembler *a) {
64356491 prev_lineno = b -> b_instr [i ].i_lineno ;
64366492 }
64376493 }
6438-
6494+ if (!b -> b_nofallthrough && b -> b_next -> b_predecessors == 1 ) {
6495+ assert (b -> b_next -> b_iused );
6496+ if (b -> b_next -> b_instr [0 ].i_lineno < 0 ) {
6497+ b -> b_next -> b_instr [0 ].i_lineno = prev_lineno ;
6498+ }
6499+ }
6500+ if (is_jump (& b -> b_instr [b -> b_iused - 1 ])) {
6501+ switch (b -> b_instr [b -> b_iused - 1 ].i_opcode ) {
6502+ /* Note: Only actual jumps, not exception handlers */
6503+ case SETUP_ASYNC_WITH :
6504+ case SETUP_WITH :
6505+ case SETUP_FINALLY :
6506+ continue ;
6507+ }
6508+ basicblock * target = b -> b_instr [b -> b_iused - 1 ].i_target ;
6509+ if (target -> b_predecessors == 1 ) {
6510+ if (target -> b_instr [0 ].i_lineno < 0 ) {
6511+ target -> b_instr [0 ].i_lineno = prev_lineno ;
6512+ }
6513+ }
6514+ }
64396515 }
64406516}
64416517
@@ -6456,35 +6532,34 @@ optimize_cfg(struct assembler *a, PyObject *consts)
64566532 return -1 ;
64576533 }
64586534 clean_basic_block (b );
6459- assert (b -> b_reachable == 0 );
6535+ assert (b -> b_predecessors == 0 );
64606536 }
64616537 if (mark_reachable (a )) {
64626538 return -1 ;
64636539 }
64646540 /* Delete unreachable instructions */
64656541 for (basicblock * b = a -> a_entry ; b != NULL ; b = b -> b_next ) {
6466- if (b -> b_reachable == 0 ) {
6542+ if (b -> b_predecessors == 0 ) {
64676543 b -> b_iused = 0 ;
64686544 b -> b_nofallthrough = 0 ;
64696545 }
64706546 }
6547+ eliminate_empty_basic_blocks (a -> a_entry );
64716548 /* Delete jump instructions made redundant by previous step. If a non-empty
64726549 block ends with a jump instruction, check if the next non-empty block
64736550 reached through normal flow control is the target of that jump. If it
64746551 is, then the jump instruction is redundant and can be deleted.
64756552 */
6553+ int maybe_empty_blocks = 0 ;
64766554 for (basicblock * b = a -> a_entry ; b != NULL ; b = b -> b_next ) {
64776555 if (b -> b_iused > 0 ) {
64786556 struct instr * b_last_instr = & b -> b_instr [b -> b_iused - 1 ];
64796557 if (b_last_instr -> i_opcode == POP_JUMP_IF_FALSE ||
64806558 b_last_instr -> i_opcode == POP_JUMP_IF_TRUE ||
64816559 b_last_instr -> i_opcode == JUMP_ABSOLUTE ||
64826560 b_last_instr -> i_opcode == JUMP_FORWARD ) {
6483- basicblock * b_next_act = b -> b_next ;
6484- while (b_next_act != NULL && b_next_act -> b_iused == 0 ) {
6485- b_next_act = b_next_act -> b_next ;
6486- }
6487- if (b_last_instr -> i_target == b_next_act ) {
6561+ if (b_last_instr -> i_target == b -> b_next ) {
6562+ assert (b -> b_next -> b_iused );
64886563 b -> b_nofallthrough = 0 ;
64896564 switch (b_last_instr -> i_opcode ) {
64906565 case POP_JUMP_IF_FALSE :
@@ -6497,19 +6572,17 @@ optimize_cfg(struct assembler *a, PyObject *consts)
64976572 case JUMP_FORWARD :
64986573 b_last_instr -> i_opcode = NOP ;
64996574 clean_basic_block (b );
6575+ maybe_empty_blocks = 1 ;
65006576 break ;
65016577 }
6502- /* The blocks after this one are now reachable through it */
6503- b_next_act = b -> b_next ;
6504- while (b_next_act != NULL && b_next_act -> b_iused == 0 ) {
6505- b_next_act -> b_reachable = 1 ;
6506- b_next_act = b_next_act -> b_next ;
6507- }
65086578 }
65096579 }
65106580 }
65116581 }
6512- minimize_lineno_table (a );
6582+ if (maybe_empty_blocks ) {
6583+ eliminate_empty_basic_blocks (a -> a_entry );
6584+ }
6585+ propogate_line_numbers (a );
65136586 return 0 ;
65146587}
65156588
0 commit comments