Skip to content

Commit c529b45

Browse files
authored
gh-87092: bring compiler code closer to a preprocessing-opt-assembler organisation (GH-97644)
1 parent 8079bef commit c529b45

File tree

2 files changed

+62
-40
lines changed

2 files changed

+62
-40
lines changed

Lib/test/test_compile.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -670,10 +670,22 @@ def test_merge_code_attrs(self):
670670

671671
self.assertIs(f1.__code__.co_linetable, f2.__code__.co_linetable)
672672

673+
@support.cpython_only
674+
def test_strip_unused_consts(self):
675+
def f():
676+
"docstring"
677+
if True:
678+
return "used"
679+
else:
680+
return "unused"
681+
682+
self.assertEqual(f.__code__.co_consts,
683+
("docstring", True, "used"))
684+
673685
# Stripping unused constants is not a strict requirement for the
674686
# Python semantics, it's a more an implementation detail.
675687
@support.cpython_only
676-
def test_strip_unused_consts(self):
688+
def test_strip_unused_None(self):
677689
# Python 3.10rc1 appended None to co_consts when None is not used
678690
# at all. See bpo-45056.
679691
def f1():

Python/compile.c

+49-39
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,19 @@ cfg_builder_use_label(cfg_builder *g, jump_target_label lbl)
912912
return cfg_builder_maybe_start_new_block(g);
913913
}
914914

915+
static inline int
916+
basicblock_append_instructions(basicblock *target, basicblock *source)
917+
{
918+
for (int i = 0; i < source->b_iused; i++) {
919+
int n = basicblock_next_instr(target);
920+
if (n < 0) {
921+
return -1;
922+
}
923+
target->b_instr[n] = source->b_instr[i];
924+
}
925+
return 0;
926+
}
927+
915928
static basicblock *
916929
copy_basicblock(cfg_builder *g, basicblock *block)
917930
{
@@ -923,12 +936,8 @@ copy_basicblock(cfg_builder *g, basicblock *block)
923936
if (result == NULL) {
924937
return NULL;
925938
}
926-
for (int i = 0; i < block->b_iused; i++) {
927-
int n = basicblock_next_instr(result);
928-
if (n < 0) {
929-
return NULL;
930-
}
931-
result->b_instr[n] = block->b_instr[i];
939+
if (basicblock_append_instructions(result, block) < 0) {
940+
return NULL;
932941
}
933942
return result;
934943
}
@@ -7080,15 +7089,14 @@ stackdepth(basicblock *entryblock, int code_flags)
70807089
if (new_depth > maxdepth) {
70817090
maxdepth = new_depth;
70827091
}
7083-
assert(depth >= 0); /* invalid code or bug in stackdepth() */
70847092
if (HAS_TARGET(instr->i_opcode)) {
70857093
effect = stack_effect(instr->i_opcode, instr->i_oparg, 1);
70867094
assert(effect != PY_INVALID_STACK_EFFECT);
70877095
int target_depth = depth + effect;
7096+
assert(target_depth >= 0); /* invalid code or bug in stackdepth() */
70887097
if (target_depth > maxdepth) {
70897098
maxdepth = target_depth;
70907099
}
7091-
assert(target_depth >= 0); /* invalid code or bug in stackdepth() */
70927100
stackdepth_push(&sp, instr->i_target, target_depth);
70937101
}
70947102
depth = new_depth;
@@ -7487,6 +7495,9 @@ convert_exception_handlers_to_nops(basicblock *entryblock) {
74877495
}
74887496
}
74897497
}
7498+
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
7499+
remove_redundant_nops(b);
7500+
}
74907501
}
74917502

74927503
static inline void
@@ -7964,8 +7975,8 @@ scan_block_for_local(int target, basicblock *b, bool unsafe_to_start,
79647975
#undef MAYBE_PUSH
79657976

79667977
static int
7967-
add_checks_for_loads_of_unknown_variables(basicblock *entryblock,
7968-
struct compiler *c)
7978+
add_checks_for_loads_of_uninitialized_variables(basicblock *entryblock,
7979+
struct compiler *c)
79697980
{
79707981
basicblock **stack = make_cfg_traversal_stack(entryblock);
79717982
if (stack == NULL) {
@@ -8291,7 +8302,7 @@ dump_basicblock(const basicblock *b)
82918302

82928303

82938304
static int
8294-
calculate_jump_targets(basicblock *entryblock);
8305+
translate_jump_labels_to_targets(basicblock *entryblock);
82958306

82968307
static int
82978308
optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache);
@@ -8628,11 +8639,9 @@ assemble(struct compiler *c, int addNone)
86288639
}
86298640
nlocalsplus -= numdropped;
86308641

8631-
consts = consts_dict_keys_inorder(c->u->u_consts);
8632-
if (consts == NULL) {
8633-
goto error;
8634-
}
8635-
if (calculate_jump_targets(g->g_entryblock)) {
8642+
/** Preprocessing **/
8643+
/* Map labels to targets and mark exception handlers */
8644+
if (translate_jump_labels_to_targets(g->g_entryblock)) {
86368645
goto error;
86378646
}
86388647
if (mark_except_handlers(g->g_entryblock) < 0) {
@@ -8641,18 +8650,31 @@ assemble(struct compiler *c, int addNone)
86418650
if (label_exception_targets(g->g_entryblock)) {
86428651
goto error;
86438652
}
8653+
8654+
/** Optimization **/
8655+
consts = consts_dict_keys_inorder(c->u->u_consts);
8656+
if (consts == NULL) {
8657+
goto error;
8658+
}
86448659
if (optimize_cfg(g, consts, c->c_const_cache)) {
86458660
goto error;
86468661
}
8647-
if (trim_unused_consts(g->g_entryblock, consts)) {
8662+
if (add_checks_for_loads_of_uninitialized_variables(g->g_entryblock, c) < 0) {
86488663
goto error;
86498664
}
8665+
8666+
/** line numbers (TODO: move this before optimization stage) */
86508667
if (duplicate_exits_without_lineno(g) < 0) {
86518668
goto error;
86528669
}
86538670
propagate_line_numbers(g->g_entryblock);
86548671
guarantee_lineno_for_exits(g->g_entryblock, c->u->u_firstlineno);
86558672

8673+
if (push_cold_blocks_to_end(g, code_flags) < 0) {
8674+
goto error;
8675+
}
8676+
8677+
/** Assembly **/
86568678
int maxdepth = stackdepth(g->g_entryblock, code_flags);
86578679
if (maxdepth < 0) {
86588680
goto error;
@@ -8661,27 +8683,19 @@ assemble(struct compiler *c, int addNone)
86618683

86628684
convert_exception_handlers_to_nops(g->g_entryblock);
86638685

8664-
if (push_cold_blocks_to_end(g, code_flags) < 0) {
8665-
goto error;
8666-
}
8667-
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
8668-
remove_redundant_nops(b);
8669-
}
8670-
86718686
/* Order of basic blocks must have been determined by now */
86728687
if (normalize_jumps(g) < 0) {
86738688
goto error;
86748689
}
86758690

8676-
if (add_checks_for_loads_of_unknown_variables(g->g_entryblock, c) < 0) {
8677-
goto error;
8678-
}
8679-
86808691
assert(no_redundant_jumps(g));
86818692

86828693
/* Can't modify the bytecode after computing jump offsets. */
86838694
assemble_jump_offsets(g->g_entryblock);
86848695

8696+
if (trim_unused_consts(g->g_entryblock, consts)) {
8697+
goto error;
8698+
}
86858699

86868700
/* Create assembler */
86878701
if (!assemble_init(&a, c->u->u_firstlineno))
@@ -9265,12 +9279,8 @@ inline_small_exit_blocks(basicblock *bb) {
92659279
basicblock *target = last->i_target;
92669280
if (basicblock_exits_scope(target) && target->b_iused <= MAX_COPY_SIZE) {
92679281
last->i_opcode = NOP;
9268-
for (int i = 0; i < target->b_iused; i++) {
9269-
int index = basicblock_next_instr(bb);
9270-
if (index < 0) {
9271-
return -1;
9272-
}
9273-
bb->b_instr[index] = target->b_instr[i];
9282+
if (basicblock_append_instructions(bb, target) < 0) {
9283+
return -1;
92749284
}
92759285
return 1;
92769286
}
@@ -9456,7 +9466,7 @@ propagate_line_numbers(basicblock *entryblock) {
94569466

94579467
/* Calculate the actual jump target from the target_label */
94589468
static int
9459-
calculate_jump_targets(basicblock *entryblock)
9469+
translate_jump_labels_to_targets(basicblock *entryblock)
94609470
{
94619471
int max_label = -1;
94629472
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
@@ -9599,12 +9609,14 @@ is_exit_without_lineno(basicblock *b) {
95999609
static int
96009610
duplicate_exits_without_lineno(cfg_builder *g)
96019611
{
9612+
assert(no_empty_basic_blocks(g));
96029613
/* Copy all exit blocks without line number that are targets of a jump.
96039614
*/
96049615
basicblock *entryblock = g->g_entryblock;
96059616
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
96069617
struct instr *last = basicblock_last_instr(b);
9607-
if (last != NULL && is_jump(last)) {
9618+
assert(last != NULL);
9619+
if (is_jump(last)) {
96089620
basicblock *target = last->i_target;
96099621
if (is_exit_without_lineno(target) && target->b_predecessors > 1) {
96109622
basicblock *new_target = copy_basicblock(g, target);
@@ -9621,8 +9633,6 @@ duplicate_exits_without_lineno(cfg_builder *g)
96219633
}
96229634
}
96239635

9624-
assert(no_empty_basic_blocks(g));
9625-
96269636
/* Any remaining reachable exit blocks without line number can only be reached by
96279637
* fall through, and thus can only have a single predecessor */
96289638
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
@@ -9775,7 +9785,7 @@ _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts)
97759785
if (const_cache == NULL) {
97769786
goto error;
97779787
}
9778-
if (calculate_jump_targets(g.g_entryblock)) {
9788+
if (translate_jump_labels_to_targets(g.g_entryblock)) {
97799789
goto error;
97809790
}
97819791
if (optimize_cfg(&g, consts, const_cache) < 0) {

0 commit comments

Comments
 (0)