@@ -498,7 +498,7 @@ static int compiler_match(struct compiler *, stmt_ty);
498
498
static int compiler_pattern_subpattern (struct compiler * , pattern_ty ,
499
499
pattern_context * );
500
500
501
- static void clean_basic_block (basicblock * bb );
501
+ static void remove_redundant_nops (basicblock * bb );
502
502
503
503
static PyCodeObject * assemble (struct compiler * , int addNone );
504
504
@@ -7364,7 +7364,7 @@ mark_cold(basicblock *entryblock) {
7364
7364
for (int i = 0 ; i < b -> b_iused ; i ++ ) {
7365
7365
struct instr * instr = & b -> b_instr [i ];
7366
7366
if (is_jump (instr )) {
7367
- assert (i == b -> b_iused - 1 );
7367
+ assert (i == b -> b_iused - 1 );
7368
7368
basicblock * target = b -> b_instr [i ].i_target ;
7369
7369
if (!target -> b_warm && !target -> b_visited ) {
7370
7370
* sp ++ = target ;
@@ -8271,9 +8271,6 @@ dump_basicblock(const basicblock *b)
8271
8271
#endif
8272
8272
8273
8273
8274
- static int
8275
- normalize_basic_block (basicblock * bb );
8276
-
8277
8274
static int
8278
8275
calculate_jump_targets (basicblock * entryblock );
8279
8276
@@ -8325,7 +8322,7 @@ insert_instruction(basicblock *block, int pos, struct instr *instr) {
8325
8322
if (basicblock_next_instr (block ) < 0 ) {
8326
8323
return -1 ;
8327
8324
}
8328
- for (int i = block -> b_iused - 1 ; i > pos ; i -- ) {
8325
+ for (int i = block -> b_iused - 1 ; i > pos ; i -- ) {
8329
8326
block -> b_instr [i ] = block -> b_instr [i - 1 ];
8330
8327
}
8331
8328
block -> b_instr [pos ] = * instr ;
@@ -8488,23 +8485,32 @@ fix_cell_offsets(struct compiler *c, basicblock *entryblock, int *fixedmap)
8488
8485
static void
8489
8486
propagate_line_numbers (basicblock * entryblock );
8490
8487
8491
- static void
8492
- eliminate_empty_basic_blocks (cfg_builder * g );
8493
-
8494
8488
#ifndef NDEBUG
8495
8489
static bool
8496
8490
no_redundant_jumps (cfg_builder * g ) {
8497
8491
for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
8498
8492
struct instr * last = basicblock_last_instr (b );
8499
8493
if (last != NULL ) {
8500
- if (last -> i_opcode == JUMP || last -> i_opcode == JUMP_NO_INTERRUPT ) {
8494
+ if (IS_UNCONDITIONAL_JUMP_OPCODE ( last -> i_opcode ) ) {
8501
8495
assert (last -> i_target != b -> b_next );
8502
- return false;
8496
+ if (last -> i_target == b -> b_next ) {
8497
+ return false;
8498
+ }
8503
8499
}
8504
8500
}
8505
8501
}
8506
8502
return true;
8507
8503
}
8504
+
8505
+ static bool
8506
+ no_empty_basic_blocks (cfg_builder * g ) {
8507
+ for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
8508
+ if (b -> b_iused == 0 ) {
8509
+ return false;
8510
+ }
8511
+ }
8512
+ return true;
8513
+ }
8508
8514
#endif
8509
8515
8510
8516
static int
@@ -8514,28 +8520,22 @@ remove_redundant_jumps(cfg_builder *g) {
8514
8520
* of that jump. If it is, then the jump instruction is redundant and
8515
8521
* can be deleted.
8516
8522
*/
8517
- int removed = 0 ;
8523
+ assert ( no_empty_basic_blocks ( g )) ;
8518
8524
for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
8519
8525
struct instr * last = basicblock_last_instr (b );
8520
- if (last != NULL ) {
8521
- assert (!IS_ASSEMBLER_OPCODE (last -> i_opcode ));
8522
- if (last -> i_opcode == JUMP ||
8523
- last -> i_opcode == JUMP_NO_INTERRUPT ) {
8524
- if (last -> i_target == NULL ) {
8525
- PyErr_SetString (PyExc_SystemError , "jump with NULL target" );
8526
- return -1 ;
8527
- }
8528
- if (last -> i_target == b -> b_next ) {
8529
- assert (b -> b_next -> b_iused );
8530
- last -> i_opcode = NOP ;
8531
- removed ++ ;
8532
- }
8526
+ assert (last != NULL );
8527
+ assert (!IS_ASSEMBLER_OPCODE (last -> i_opcode ));
8528
+ if (IS_UNCONDITIONAL_JUMP_OPCODE (last -> i_opcode )) {
8529
+ if (last -> i_target == NULL ) {
8530
+ PyErr_SetString (PyExc_SystemError , "jump with NULL target" );
8531
+ return -1 ;
8532
+ }
8533
+ if (last -> i_target == b -> b_next ) {
8534
+ assert (b -> b_next -> b_iused );
8535
+ last -> i_opcode = NOP ;
8533
8536
}
8534
8537
}
8535
8538
}
8536
- if (removed ) {
8537
- eliminate_empty_basic_blocks (g );
8538
- }
8539
8539
return 0 ;
8540
8540
}
8541
8541
@@ -8643,7 +8643,7 @@ assemble(struct compiler *c, int addNone)
8643
8643
goto error ;
8644
8644
}
8645
8645
for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
8646
- clean_basic_block (b );
8646
+ remove_redundant_nops (b );
8647
8647
}
8648
8648
8649
8649
/* Order of basic blocks must have been determined by now */
@@ -9003,10 +9003,7 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
9003
9003
int oparg = inst -> i_oparg ;
9004
9004
int nextop = i + 1 < bb -> b_iused ? bb -> b_instr [i + 1 ].i_opcode : 0 ;
9005
9005
if (HAS_TARGET (inst -> i_opcode )) {
9006
- /* Skip over empty basic blocks. */
9007
- while (inst -> i_target -> b_iused == 0 ) {
9008
- inst -> i_target = inst -> i_target -> b_next ;
9009
- }
9006
+ assert (inst -> i_target -> b_iused > 0 );
9010
9007
target = & inst -> i_target -> b_instr [0 ];
9011
9008
assert (!IS_ASSEMBLER_OPCODE (target -> i_opcode ));
9012
9009
}
@@ -9230,50 +9227,36 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
9230
9227
return -1 ;
9231
9228
}
9232
9229
9233
- static bool
9234
- basicblock_has_lineno (const basicblock * bb ) {
9235
- for (int i = 0 ; i < bb -> b_iused ; i ++ ) {
9236
- if (bb -> b_instr [i ].i_loc .lineno > 0 ) {
9237
- return true;
9238
- }
9239
- }
9240
- return false;
9241
- }
9242
-
9243
- /* If this block ends with an unconditional jump to an exit block,
9244
- * then remove the jump and extend this block with the target.
9230
+ /* If this block ends with an unconditional jump to a small exit block, then
9231
+ * remove the jump and extend this block with the target.
9232
+ * Returns 1 if extended, 0 if no change, and -1 on error.
9245
9233
*/
9246
9234
static int
9247
- extend_block (basicblock * bb ) {
9235
+ inline_small_exit_blocks (basicblock * bb ) {
9248
9236
struct instr * last = basicblock_last_instr (bb );
9249
9237
if (last == NULL ) {
9250
9238
return 0 ;
9251
9239
}
9252
- if (last -> i_opcode != JUMP &&
9253
- last -> i_opcode != JUMP_FORWARD &&
9254
- last -> i_opcode != JUMP_BACKWARD ) {
9240
+ if (!IS_UNCONDITIONAL_JUMP_OPCODE (last -> i_opcode )) {
9255
9241
return 0 ;
9256
9242
}
9257
- if (basicblock_exits_scope (last -> i_target ) && last -> i_target -> b_iused <= MAX_COPY_SIZE ) {
9258
- basicblock * to_copy = last -> i_target ;
9259
- if (basicblock_has_lineno (to_copy )) {
9260
- /* copy only blocks without line number (like implicit 'return None's) */
9261
- return 0 ;
9262
- }
9243
+ basicblock * target = last -> i_target ;
9244
+ if (basicblock_exits_scope (target ) && target -> b_iused <= MAX_COPY_SIZE ) {
9263
9245
last -> i_opcode = NOP ;
9264
- for (int i = 0 ; i < to_copy -> b_iused ; i ++ ) {
9246
+ for (int i = 0 ; i < target -> b_iused ; i ++ ) {
9265
9247
int index = basicblock_next_instr (bb );
9266
9248
if (index < 0 ) {
9267
9249
return -1 ;
9268
9250
}
9269
- bb -> b_instr [index ] = to_copy -> b_instr [i ];
9251
+ bb -> b_instr [index ] = target -> b_instr [i ];
9270
9252
}
9253
+ return 1 ;
9271
9254
}
9272
9255
return 0 ;
9273
9256
}
9274
9257
9275
9258
static void
9276
- clean_basic_block (basicblock * bb ) {
9259
+ remove_redundant_nops (basicblock * bb ) {
9277
9260
/* Remove NOPs when legal to do so. */
9278
9261
int dest = 0 ;
9279
9262
int prev_lineno = -1 ;
@@ -9324,24 +9307,17 @@ clean_basic_block(basicblock *bb) {
9324
9307
}
9325
9308
9326
9309
static int
9327
- normalize_basic_block (basicblock * bb ) {
9328
- /* Skip over empty blocks.
9329
- * Raise SystemError if jump or exit is not last instruction in the block. */
9330
- for (int i = 0 ; i < bb -> b_iused ; i ++ ) {
9331
- int opcode = bb -> b_instr [i ].i_opcode ;
9332
- assert (!IS_ASSEMBLER_OPCODE (opcode ));
9333
- int is_jump = IS_JUMP_OPCODE (opcode );
9334
- int is_exit = IS_SCOPE_EXIT_OPCODE (opcode );
9335
- if (is_exit || is_jump ) {
9336
- if (i != bb -> b_iused - 1 ) {
9337
- PyErr_SetString (PyExc_SystemError , "malformed control flow graph." );
9338
- return -1 ;
9339
- }
9340
- }
9341
- if (is_jump ) {
9342
- /* Skip over empty basic blocks. */
9343
- while (bb -> b_instr [i ].i_target -> b_iused == 0 ) {
9344
- bb -> b_instr [i ].i_target = bb -> b_instr [i ].i_target -> b_next ;
9310
+ check_cfg (cfg_builder * g ) {
9311
+ for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
9312
+ /* Raise SystemError if jump or exit is not last instruction in the block. */
9313
+ for (int i = 0 ; i < b -> b_iused ; i ++ ) {
9314
+ int opcode = b -> b_instr [i ].i_opcode ;
9315
+ assert (!IS_ASSEMBLER_OPCODE (opcode ));
9316
+ if (IS_TERMINATOR_OPCODE (opcode )) {
9317
+ if (i != b -> b_iused - 1 ) {
9318
+ PyErr_SetString (PyExc_SystemError , "malformed control flow graph." );
9319
+ return -1 ;
9320
+ }
9345
9321
}
9346
9322
}
9347
9323
}
@@ -9512,25 +9488,25 @@ static int
9512
9488
optimize_cfg (cfg_builder * g , PyObject * consts , PyObject * const_cache )
9513
9489
{
9514
9490
assert (PyDict_CheckExact (const_cache ));
9515
- for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
9516
- if (normalize_basic_block (b )) {
9517
- return -1 ;
9518
- }
9491
+ if (check_cfg (g ) < 0 ) {
9492
+ return -1 ;
9519
9493
}
9494
+ eliminate_empty_basic_blocks (g );
9520
9495
for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
9521
- if (extend_block (b ) < 0 ) {
9496
+ if (inline_small_exit_blocks (b ) < 0 ) {
9522
9497
return -1 ;
9523
9498
}
9524
9499
}
9500
+ assert (no_empty_basic_blocks (g ));
9525
9501
for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
9526
9502
if (optimize_basic_block (const_cache , b , consts )) {
9527
9503
return -1 ;
9528
9504
}
9529
- clean_basic_block (b );
9505
+ remove_redundant_nops (b );
9530
9506
assert (b -> b_predecessors == 0 );
9531
9507
}
9532
9508
for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
9533
- if (extend_block (b ) < 0 ) {
9509
+ if (inline_small_exit_blocks (b ) < 0 ) {
9534
9510
return -1 ;
9535
9511
}
9536
9512
}
@@ -9545,7 +9521,7 @@ optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache)
9545
9521
}
9546
9522
eliminate_empty_basic_blocks (g );
9547
9523
for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
9548
- clean_basic_block (b );
9524
+ remove_redundant_nops (b );
9549
9525
}
9550
9526
if (remove_redundant_jumps (g ) < 0 ) {
9551
9527
return -1 ;
@@ -9627,12 +9603,9 @@ duplicate_exits_without_lineno(cfg_builder *g)
9627
9603
}
9628
9604
}
9629
9605
}
9630
- /* Eliminate empty blocks */
9631
- for (basicblock * b = entryblock ; b != NULL ; b = b -> b_next ) {
9632
- while (b -> b_next && b -> b_next -> b_iused == 0 ) {
9633
- b -> b_next = b -> b_next -> b_next ;
9634
- }
9635
- }
9606
+
9607
+ assert (no_empty_basic_blocks (g ));
9608
+
9636
9609
/* Any remaining reachable exit blocks without line number can only be reached by
9637
9610
* fall through, and thus can only have a single predecessor */
9638
9611
for (basicblock * b = entryblock ; b != NULL ; b = b -> b_next ) {
0 commit comments