Skip to content

Commit 7d01fb4

Browse files
authored
gh-113603: Compiler no longer tries to maintain the no-empty-block invariant (#113636)
1 parent 0c3455a commit 7d01fb4

File tree

3 files changed

+52
-78
lines changed

3 files changed

+52
-78
lines changed

Lib/test/test_compile.py

+13
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,19 @@ def test_condition_expression_with_dead_blocks_compiles(self):
448448
# See gh-113054
449449
compile('if (5 if 5 else T): 0', '<eval>', 'exec')
450450

451+
def test_condition_expression_with_redundant_comparisons_compiles(self):
452+
# See gh-113054
453+
compile('if 9<9<9and 9or 9:9', '<eval>', 'exec')
454+
455+
def test_dead_code_with_except_handler_compiles(self):
456+
compile(textwrap.dedent("""
457+
if None:
458+
with CM:
459+
x = 1
460+
else:
461+
x = 2
462+
"""), '<eval>', 'exec')
463+
451464
def test_compile_invalid_namedexpr(self):
452465
# gh-109351
453466
m = ast.Module(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed bug where a redundant NOP is not removed, causing an assertion to fail in the compiler in debug mode.

Python/flowgraph.c

+38-78
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,15 @@ _PyCfgBuilder_Addop(cfg_builder *g, int opcode, int oparg, location loc)
449449
}
450450

451451

452+
static basicblock *
453+
next_nonempty_block(basicblock *b)
454+
{
455+
while (b && b->b_iused == 0) {
456+
b = b->b_next;
457+
}
458+
return b;
459+
}
460+
452461
/***** debugging helpers *****/
453462

454463
#ifndef NDEBUG
@@ -464,24 +473,16 @@ no_redundant_nops(cfg_builder *g) {
464473
return true;
465474
}
466475

467-
static bool
468-
no_empty_basic_blocks(cfg_builder *g) {
469-
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
470-
if (b->b_iused == 0) {
471-
return false;
472-
}
473-
}
474-
return true;
475-
}
476-
477476
static bool
478477
no_redundant_jumps(cfg_builder *g) {
479478
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
480479
cfg_instr *last = basicblock_last_instr(b);
481480
if (last != NULL) {
482481
if (IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) {
483-
assert(last->i_target != b->b_next);
484-
if (last->i_target == b->b_next) {
482+
basicblock *next = next_nonempty_block(b->b_next);
483+
basicblock *jump_target = next_nonempty_block(last->i_target);
484+
assert(jump_target != next);
485+
if (jump_target == next) {
485486
return false;
486487
}
487488
}
@@ -961,42 +962,6 @@ mark_reachable(basicblock *entryblock) {
961962
return SUCCESS;
962963
}
963964

964-
static void
965-
eliminate_empty_basic_blocks(cfg_builder *g) {
966-
/* Eliminate empty blocks */
967-
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
968-
basicblock *next = b->b_next;
969-
while (next && next->b_iused == 0) {
970-
next = next->b_next;
971-
}
972-
b->b_next = next;
973-
}
974-
while(g->g_entryblock && g->g_entryblock->b_iused == 0) {
975-
g->g_entryblock = g->g_entryblock->b_next;
976-
}
977-
int next_lbl = get_max_label(g->g_entryblock) + 1;
978-
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
979-
assert(b->b_iused > 0);
980-
for (int i = 0; i < b->b_iused; i++) {
981-
cfg_instr *instr = &b->b_instr[i];
982-
if (HAS_TARGET(instr->i_opcode)) {
983-
basicblock *target = instr->i_target;
984-
while (target->b_iused == 0) {
985-
target = target->b_next;
986-
}
987-
if (instr->i_target != target) {
988-
if (!IS_LABEL(target->b_label)) {
989-
target->b_label.id = next_lbl++;
990-
}
991-
instr->i_target = target;
992-
instr->i_oparg = target->b_label.id;
993-
}
994-
assert(instr->i_target && instr->i_target->b_iused > 0);
995-
}
996-
}
997-
}
998-
}
999-
1000965
static int
1001966
remove_redundant_nops(basicblock *bb) {
1002967
/* Remove NOPs when legal to do so. */
@@ -1025,10 +990,7 @@ remove_redundant_nops(basicblock *bb) {
1025990
}
1026991
}
1027992
else {
1028-
basicblock* next = bb->b_next;
1029-
while (next && next->b_iused == 0) {
1030-
next = next->b_next;
1031-
}
993+
basicblock *next = next_nonempty_block(bb->b_next);
1032994
/* or if last instruction in BB and next BB has same line number */
1033995
if (next) {
1034996
location next_loc = NO_LOCATION;
@@ -1112,36 +1074,29 @@ remove_redundant_jumps(cfg_builder *g) {
11121074
* can be deleted.
11131075
*/
11141076

1115-
assert(no_empty_basic_blocks(g));
1116-
1117-
bool remove_empty_blocks = false;
11181077
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
11191078
cfg_instr *last = basicblock_last_instr(b);
1120-
assert(last != NULL);
1079+
if (last == NULL) {
1080+
continue;
1081+
}
11211082
assert(!IS_ASSEMBLER_OPCODE(last->i_opcode));
11221083
if (IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) {
1123-
if (last->i_target == NULL) {
1084+
basicblock* jump_target = next_nonempty_block(last->i_target);
1085+
if (jump_target == NULL) {
11241086
PyErr_SetString(PyExc_SystemError, "jump with NULL target");
11251087
return ERROR;
11261088
}
1127-
if (last->i_target == b->b_next) {
1128-
assert(b->b_next->b_iused);
1089+
basicblock *next = next_nonempty_block(b->b_next);
1090+
if (jump_target == next) {
11291091
if (last->i_loc.lineno == NO_LOCATION.lineno) {
11301092
b->b_iused--;
1131-
if (b->b_iused == 0) {
1132-
remove_empty_blocks = true;
1133-
}
11341093
}
11351094
else {
11361095
INSTR_SET_OP0(last, NOP);
11371096
}
11381097
}
11391098
}
11401099
}
1141-
if (remove_empty_blocks) {
1142-
eliminate_empty_basic_blocks(g);
1143-
}
1144-
assert(no_empty_basic_blocks(g));
11451100
return SUCCESS;
11461101
}
11471102

@@ -1749,11 +1704,9 @@ optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache)
17491704
{
17501705
assert(PyDict_CheckExact(const_cache));
17511706
RETURN_IF_ERROR(check_cfg(g));
1752-
eliminate_empty_basic_blocks(g);
17531707
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
17541708
RETURN_IF_ERROR(inline_small_exit_blocks(b));
17551709
}
1756-
assert(no_empty_basic_blocks(g));
17571710
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
17581711
RETURN_IF_ERROR(optimize_basic_block(const_cache, b, consts));
17591712
assert(b->b_predecessors == 0);
@@ -1768,14 +1721,21 @@ optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache)
17681721
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
17691722
if (b->b_predecessors == 0) {
17701723
b->b_iused = 0;
1724+
b->b_except_handler = 0;
17711725
}
17721726
}
17731727
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
17741728
remove_redundant_nops(b);
17751729
}
1776-
eliminate_empty_basic_blocks(g);
1777-
assert(no_redundant_nops(g));
17781730
RETURN_IF_ERROR(remove_redundant_jumps(g));
1731+
1732+
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
1733+
remove_redundant_nops(b);
1734+
}
1735+
1736+
RETURN_IF_ERROR(remove_redundant_jumps(g));
1737+
1738+
assert(no_redundant_jumps(g));
17791739
return SUCCESS;
17801740
}
17811741

@@ -1825,7 +1785,6 @@ insert_superinstructions(cfg_builder *g)
18251785
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
18261786
remove_redundant_nops(b);
18271787
}
1828-
eliminate_empty_basic_blocks(g);
18291788
assert(no_redundant_nops(g));
18301789
}
18311790

@@ -2299,18 +2258,18 @@ is_exit_without_lineno(basicblock *b) {
22992258
static int
23002259
duplicate_exits_without_lineno(cfg_builder *g)
23012260
{
2302-
assert(no_empty_basic_blocks(g));
2303-
23042261
int next_lbl = get_max_label(g->g_entryblock) + 1;
23052262

23062263
/* Copy all exit blocks without line number that are targets of a jump.
23072264
*/
23082265
basicblock *entryblock = g->g_entryblock;
23092266
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
23102267
cfg_instr *last = basicblock_last_instr(b);
2311-
assert(last != NULL);
2268+
if (last == NULL) {
2269+
continue;
2270+
}
23122271
if (is_jump(last)) {
2313-
basicblock *target = last->i_target;
2272+
basicblock *target = next_nonempty_block(last->i_target);
23142273
if (is_exit_without_lineno(target) && target->b_predecessors > 1) {
23152274
basicblock *new_target = copy_basicblock(g, target);
23162275
if (new_target == NULL) {
@@ -2367,9 +2326,10 @@ propagate_line_numbers(basicblock *entryblock) {
23672326
}
23682327
}
23692328
if (BB_HAS_FALLTHROUGH(b) && b->b_next->b_predecessors == 1) {
2370-
assert(b->b_next->b_iused);
2371-
if (b->b_next->b_instr[0].i_loc.lineno < 0) {
2372-
b->b_next->b_instr[0].i_loc = prev_location;
2329+
if (b->b_next->b_iused > 0) {
2330+
if (b->b_next->b_instr[0].i_loc.lineno < 0) {
2331+
b->b_next->b_instr[0].i_loc = prev_location;
2332+
}
23732333
}
23742334
}
23752335
if (is_jump(last)) {

0 commit comments

Comments
 (0)