Skip to content

Commit 4784a0d

Browse files
committed
pythongh-113054: Compiler no longer tries to maintain the no-empty-block invariant
1 parent 45e09f9 commit 4784a0d

File tree

2 files changed

+38
-75
lines changed

2 files changed

+38
-75
lines changed

Lib/test/test_compile.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,10 @@ 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+
451455
def test_compile_invalid_namedexpr(self):
452456
# gh-109351
453457
m = ast.Module(

Python/flowgraph.c

Lines changed: 34 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -464,14 +464,13 @@ no_redundant_nops(cfg_builder *g) {
464464
return true;
465465
}
466466

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-
}
467+
static basicblock*
468+
next_nonempty_block(basicblock *b)
469+
{
470+
while (b && b->b_iused == 0) {
471+
b = b->b_next;
473472
}
474-
return true;
473+
return b;
475474
}
476475

477476
static bool
@@ -480,8 +479,10 @@ no_redundant_jumps(cfg_builder *g) {
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);
@@ -1773,9 +1726,15 @@ optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache)
17731726
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
17741727
remove_redundant_nops(b);
17751728
}
1776-
eliminate_empty_basic_blocks(g);
1777-
assert(no_redundant_nops(g));
17781729
RETURN_IF_ERROR(remove_redundant_jumps(g));
1730+
1731+
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
1732+
remove_redundant_nops(b);
1733+
}
1734+
1735+
RETURN_IF_ERROR(remove_redundant_jumps(g));
1736+
1737+
assert(no_redundant_jumps(g));
17791738
return SUCCESS;
17801739
}
17811740

@@ -1825,7 +1784,6 @@ insert_superinstructions(cfg_builder *g)
18251784
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
18261785
remove_redundant_nops(b);
18271786
}
1828-
eliminate_empty_basic_blocks(g);
18291787
assert(no_redundant_nops(g));
18301788
}
18311789

@@ -2299,18 +2257,18 @@ is_exit_without_lineno(basicblock *b) {
22992257
static int
23002258
duplicate_exits_without_lineno(cfg_builder *g)
23012259
{
2302-
assert(no_empty_basic_blocks(g));
2303-
23042260
int next_lbl = get_max_label(g->g_entryblock) + 1;
23052261

23062262
/* Copy all exit blocks without line number that are targets of a jump.
23072263
*/
23082264
basicblock *entryblock = g->g_entryblock;
23092265
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
23102266
cfg_instr *last = basicblock_last_instr(b);
2311-
assert(last != NULL);
2267+
if (last == NULL) {
2268+
continue;
2269+
}
23122270
if (is_jump(last)) {
2313-
basicblock *target = last->i_target;
2271+
basicblock *target = next_nonempty_block(last->i_target);
23142272
if (is_exit_without_lineno(target) && target->b_predecessors > 1) {
23152273
basicblock *new_target = copy_basicblock(g, target);
23162274
if (new_target == NULL) {
@@ -2367,9 +2325,10 @@ propagate_line_numbers(basicblock *entryblock) {
23672325
}
23682326
}
23692327
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;
2328+
if (b->b_next->b_iused > 0) {
2329+
if (b->b_next->b_instr[0].i_loc.lineno < 0) {
2330+
b->b_next->b_instr[0].i_loc = prev_location;
2331+
}
23732332
}
23742333
}
23752334
if (is_jump(last)) {

0 commit comments

Comments
 (0)