@@ -212,14 +212,14 @@ basicblock_add_jump(basicblock *b, int opcode, basicblock *target, location loc)
212212}
213213
214214static inline int
215- basicblock_append_instructions (basicblock * target , basicblock * source )
215+ basicblock_append_instructions (basicblock * to , basicblock * from )
216216{
217- for (int i = 0 ; i < source -> b_iused ; i ++ ) {
218- int n = basicblock_next_instr (target );
217+ for (int i = 0 ; i < from -> b_iused ; i ++ ) {
218+ int n = basicblock_next_instr (to );
219219 if (n < 0 ) {
220220 return ERROR ;
221221 }
222- target -> b_instr [n ] = source -> b_instr [i ];
222+ to -> b_instr [n ] = from -> b_instr [i ];
223223 }
224224 return SUCCESS ;
225225}
@@ -292,9 +292,9 @@ static void
292292dump_basicblock (const basicblock * b )
293293{
294294 const char * b_return = basicblock_returns (b ) ? "return " : "" ;
295- fprintf (stderr , "%d: [EH=%d CLD=%d WRM=%d NO_FT=%d %p] used: %d, depth: %d, %s\n" ,
295+ fprintf (stderr , "%d: [EH=%d CLD=%d WRM=%d NO_FT=%d %p] used: %d, depth: %d, preds: %d %s\n" ,
296296 b -> b_label .id , b -> b_except_handler , b -> b_cold , b -> b_warm , BB_NO_FALLTHROUGH (b ), b , b -> b_iused ,
297- b -> b_startdepth , b_return );
297+ b -> b_startdepth , b -> b_predecessors , b_return );
298298 if (b -> b_instr ) {
299299 int i ;
300300 for (i = 0 ; i < b -> b_iused ; i ++ ) {
@@ -1165,15 +1165,26 @@ remove_redundant_jumps(cfg_builder *g) {
11651165 return changes ;
11661166}
11671167
1168+ static inline bool
1169+ basicblock_has_no_lineno (basicblock * b ) {
1170+ for (int i = 0 ; i < b -> b_iused ; i ++ ) {
1171+ if (b -> b_instr [i ].i_loc .lineno >= 0 ) {
1172+ return false;
1173+ }
1174+ }
1175+ return true;
1176+ }
1177+
11681178/* Maximum size of basic block that should be copied in optimizer */
11691179#define MAX_COPY_SIZE 4
11701180
1171- /* If this block ends with an unconditional jump to a small exit block, then
1181+ /* If this block ends with an unconditional jump to a small exit block or
1182+ * a block that has no line numbers (and no fallthrough), then
11721183 * remove the jump and extend this block with the target.
11731184 * Returns 1 if extended, 0 if no change, and -1 on error.
11741185 */
11751186static int
1176- inline_small_exit_blocks (basicblock * bb ) {
1187+ basicblock_inline_small_or_no_lineno_blocks (basicblock * bb ) {
11771188 cfg_instr * last = basicblock_last_instr (bb );
11781189 if (last == NULL ) {
11791190 return 0 ;
@@ -1182,14 +1193,46 @@ inline_small_exit_blocks(basicblock *bb) {
11821193 return 0 ;
11831194 }
11841195 basicblock * target = last -> i_target ;
1185- if (basicblock_exits_scope (target ) && target -> b_iused <= MAX_COPY_SIZE ) {
1196+ bool small_exit_block = (basicblock_exits_scope (target ) &&
1197+ target -> b_iused <= MAX_COPY_SIZE );
1198+ bool no_lineno_no_fallthrough = (basicblock_has_no_lineno (target ) &&
1199+ !BB_HAS_FALLTHROUGH (target ));
1200+ if (small_exit_block || no_lineno_no_fallthrough ) {
1201+ assert (is_jump (last ));
1202+ int removed_jump_opcode = last -> i_opcode ;
11861203 INSTR_SET_OP0 (last , NOP );
11871204 RETURN_IF_ERROR (basicblock_append_instructions (bb , target ));
1205+ if (no_lineno_no_fallthrough ) {
1206+ last = basicblock_last_instr (bb );
1207+ if (IS_UNCONDITIONAL_JUMP_OPCODE (last -> i_opcode ) &&
1208+ removed_jump_opcode == JUMP )
1209+ {
1210+ /* Make sure we don't lose eval breaker checks */
1211+ last -> i_opcode = JUMP ;
1212+ }
1213+ }
1214+ target -> b_predecessors -- ;
11881215 return 1 ;
11891216 }
11901217 return 0 ;
11911218}
11921219
1220+ static int
1221+ inline_small_or_no_lineno_blocks (basicblock * entryblock ) {
1222+ bool changes ;
1223+ do {
1224+ changes = false;
1225+ for (basicblock * b = entryblock ; b != NULL ; b = b -> b_next ) {
1226+ int res = basicblock_inline_small_or_no_lineno_blocks (b );
1227+ RETURN_IF_ERROR (res );
1228+ if (res ) {
1229+ changes = true;
1230+ }
1231+ }
1232+ } while (changes ); /* every change removes a jump, ensuring convergence */
1233+ return changes ;
1234+ }
1235+
11931236// Attempt to eliminate jumps to jumps by updating inst to jump to
11941237// target->i_target using the provided opcode. Return whether or not the
11951238// optimization was successful.
@@ -1804,19 +1847,14 @@ optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache, int firstl
18041847{
18051848 assert (PyDict_CheckExact (const_cache ));
18061849 RETURN_IF_ERROR (check_cfg (g ));
1807- for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
1808- RETURN_IF_ERROR (inline_small_exit_blocks (b ));
1809- }
1850+ RETURN_IF_ERROR (inline_small_or_no_lineno_blocks (g -> g_entryblock ));
18101851 RETURN_IF_ERROR (remove_unreachable (g -> g_entryblock ));
18111852 RETURN_IF_ERROR (resolve_line_numbers (g , firstlineno ));
18121853 RETURN_IF_ERROR (optimize_load_const (const_cache , g , consts ));
18131854 for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
18141855 RETURN_IF_ERROR (optimize_basic_block (const_cache , b , consts ));
18151856 }
18161857 RETURN_IF_ERROR (remove_redundant_nops_and_pairs (g -> g_entryblock ));
1817- for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
1818- RETURN_IF_ERROR (inline_small_exit_blocks (b ));
1819- }
18201858 RETURN_IF_ERROR (remove_unreachable (g -> g_entryblock ));
18211859
18221860 int removed_nops , removed_jumps ;
@@ -2333,12 +2371,7 @@ convert_pseudo_ops(cfg_builder *g)
23332371static inline bool
23342372is_exit_or_eval_check_without_lineno (basicblock * b ) {
23352373 if (basicblock_exits_scope (b ) || basicblock_has_eval_break (b )) {
2336- for (int i = 0 ; i < b -> b_iused ; i ++ ) {
2337- if (b -> b_instr [i ].i_loc .lineno >= 0 ) {
2338- return false;
2339- }
2340- }
2341- return true;
2374+ return basicblock_has_no_lineno (b );
23422375 }
23432376 else {
23442377 return false;
0 commit comments