Skip to content
Merged
Prev Previous commit
Next Next commit
unit tests run all of the optimization stage, not just optimize_cfg
  • Loading branch information
iritkatriel committed Mar 9, 2023
commit 4e7857f10e5a2de76de9cebdfc2a046d58d03db8
2 changes: 1 addition & 1 deletion Lib/test/support/bytecode_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def normalize_insts(self, insts):
if isinstance(oparg, self.Label):
arg = oparg.value
else:
arg = oparg if opcode in self.HAS_ARG else None
arg = oparg if opcode in self.HAS_ARG else 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? And why do some of the 'NOP's below in test_peepholer.py have a None operand and some have 0?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that was just messy. I've tidied it up now. Thanks.

opcode = dis.opname[opcode]
res.append((opcode, arg, *loc))
return res
Expand Down
39 changes: 26 additions & 13 deletions Lib/test/test_peepholer.py
Original file line number Diff line number Diff line change
Expand Up @@ -995,15 +995,20 @@ def test_conditional_jump_forward_non_const_condition(self):
('LOAD_CONST', 2, 13),
lbl,
('LOAD_CONST', 3, 14),
('RETURN_VALUE', 14),
]
expected = [
expected_insts = [
('LOAD_NAME', 1, 11),
('POP_JUMP_IF_TRUE', lbl := self.Label(), 12),
('LOAD_CONST', 2, 13),
('LOAD_CONST', 1, 13),
lbl,
('LOAD_CONST', 3, 14)
('NOP', 0, 14),
('RETURN_CONST', 2, 0),
]
self.cfg_optimization_test(insts, expected, consts=list(range(5)))
self.cfg_optimization_test(insts,
expected_insts,
consts=[0, 1, 2, 3, 4],
expected_consts=[0, 2, 3])

def test_conditional_jump_forward_const_condition(self):
# The unreachable branch of the jump is removed, the jump
Expand All @@ -1015,43 +1020,51 @@ def test_conditional_jump_forward_const_condition(self):
('LOAD_CONST', 2, 13),
lbl,
('LOAD_CONST', 3, 14),
('RETURN_VALUE', 14),
]
expected = [
expected_insts = [
('NOP', None, 11),
('NOP', None, 12),
('LOAD_CONST', 3, 14)
('NOP', 0, 14),
('RETURN_CONST', 1, 0),
]
self.cfg_optimization_test(insts, expected, consts=list(range(5)))
self.cfg_optimization_test(insts,
expected_insts,
consts=[0, 1, 2, 3, 4],
expected_consts=[0, 3])

def test_conditional_jump_backward_non_const_condition(self):
insts = [
lbl1 := self.Label(),
('LOAD_NAME', 1, 11),
('POP_JUMP_IF_TRUE', lbl1, 12),
('LOAD_CONST', 2, 13),
('LOAD_NAME', 2, 13),
('RETURN_VALUE', 13),
]
expected = [
lbl := self.Label(),
('LOAD_NAME', 1, 11),
('POP_JUMP_IF_TRUE', lbl, 12),
('LOAD_CONST', 2, 13)
('LOAD_NAME', 2, 13),
('RETURN_VALUE', 13),
]
self.cfg_optimization_test(insts, expected, consts=list(range(5)))

def test_conditional_jump_backward_const_condition(self):
# The unreachable branch of the jump is removed
insts = [
lbl1 := self.Label(),
('LOAD_CONST', 1, 11),
('LOAD_CONST', 3, 11),
('POP_JUMP_IF_TRUE', lbl1, 12),
('LOAD_CONST', 2, 13),
('RETURN_VALUE', 13),
]
expected = [
expected_insts = [
lbl := self.Label(),
('NOP', None, 11),
('JUMP', lbl, 12)
('JUMP', lbl, 12),
]
self.cfg_optimization_test(insts, expected, consts=list(range(5)))
self.cfg_optimization_test(insts, expected_insts, consts=list(range(5)))


if __name__ == "__main__":
Expand Down
53 changes: 32 additions & 21 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ typedef struct basicblock_ {
block, not to be confused with b_next, which is next by control flow. */
struct basicblock_ *b_list;
/* The label of this block if it is a jump target, -1 otherwise */
int b_label;
jump_target_label b_label;
/* Exception stack at start of block, used by assembler to create the exception handling table */
ExceptStack *b_exceptstack;
/* pointer to an array of instructions, initially NULL */
Expand Down Expand Up @@ -501,7 +501,7 @@ instr_sequence_next_inst(instr_sequence *seq) {
static jump_target_label
instr_sequence_new_label(instr_sequence *seq)
{
jump_target_label lbl = {seq->s_next_free_label++};
jump_target_label lbl = {++seq->s_next_free_label};
return lbl;
}

Expand Down Expand Up @@ -1095,7 +1095,7 @@ cfg_builder_new_block(cfg_builder *g)
/* Extend the singly linked list of blocks with new block. */
b->b_list = g->g_block_list;
g->g_block_list = b;
b->b_label = -1;
b->b_label = NO_LABEL;
return b;
}

Expand Down Expand Up @@ -1276,11 +1276,21 @@ basicblock_addop(basicblock *b, int opcode, int oparg, location loc)
static bool
cfg_builder_current_block_is_terminated(cfg_builder *g)
{
if (IS_LABEL(g->g_current_label)) {
struct cfg_instr *last = basicblock_last_instr(g->g_curblock);
if (last && IS_TERMINATOR_OPCODE(last->i_opcode)) {
return true;
}
struct cfg_instr *last = basicblock_last_instr(g->g_curblock);
return last && IS_TERMINATOR_OPCODE(last->i_opcode);
if (IS_LABEL(g->g_current_label)) {
if (last || IS_LABEL(g->g_curblock->b_label)) {
return true;
}
else {
/* current block is empty, label it */
g->g_curblock->b_label = g->g_current_label;
g->g_current_label = NO_LABEL;
}
}
return false;
}

static int
Expand All @@ -1291,7 +1301,7 @@ cfg_builder_maybe_start_new_block(cfg_builder *g)
if (b == NULL) {
return ERROR;
}
b->b_label = g->g_current_label.id;
b->b_label = g->g_current_label;
g->g_current_label = NO_LABEL;
cfg_builder_use_next_block(g, b);
}
Expand Down Expand Up @@ -7380,7 +7390,7 @@ push_cold_blocks_to_end(cfg_builder *g, int code_flags) {
if (explicit_jump == NULL) {
return ERROR;
}
basicblock_addop(explicit_jump, JUMP, b->b_next->b_label, NO_LOCATION);
basicblock_addop(explicit_jump, JUMP, b->b_next->b_label.id, NO_LOCATION);
explicit_jump->b_cold = 1;
explicit_jump->b_next = b->b_next;
b->b_next = explicit_jump;
Expand Down Expand Up @@ -7768,7 +7778,7 @@ normalize_jumps_in_block(cfg_builder *g, basicblock *b) {
if (backwards_jump == NULL) {
return ERROR;
}
basicblock_addop(backwards_jump, JUMP, target->b_label, NO_LOCATION);
basicblock_addop(backwards_jump, JUMP, target->b_label.id, NO_LOCATION);
backwards_jump->b_instr[0].i_target = target;
last->i_opcode = reversed_opcode;
last->i_target = b->b_next;
Expand Down Expand Up @@ -8297,7 +8307,7 @@ dump_basicblock(const basicblock *b)
{
const char *b_return = basicblock_returns(b) ? "return " : "";
fprintf(stderr, "%d: [EH=%d CLD=%d WRM=%d NO_FT=%d %p] used: %d, depth: %d, offset: %d %s\n",
b->b_label, b->b_except_handler, b->b_cold, b->b_warm, BB_NO_FALLTHROUGH(b), b, b->b_iused,
b->b_label.id, b->b_except_handler, b->b_cold, b->b_warm, BB_NO_FALLTHROUGH(b), b, b->b_iused,
b->b_startdepth, b->b_offset, b_return);
if (b->b_instr) {
int i;
Expand Down Expand Up @@ -9535,8 +9545,8 @@ translate_jump_labels_to_targets(basicblock *entryblock)
{
int max_label = -1;
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
if (b->b_label > max_label) {
max_label = b->b_label;
if (b->b_label.id > max_label) {
max_label = b->b_label.id;
}
}
size_t mapsize = sizeof(basicblock *) * (max_label + 1);
Expand All @@ -9547,8 +9557,8 @@ translate_jump_labels_to_targets(basicblock *entryblock)
}
memset(label2block, 0, mapsize);
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
if (b->b_label >= 0) {
label2block[b->b_label] = b;
if (b->b_label.id >= 0) {
label2block[b->b_label.id] = b;
}
}
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
Expand All @@ -9560,7 +9570,7 @@ translate_jump_labels_to_targets(basicblock *entryblock)
assert(lbl >= 0 && lbl <= max_label);
instr->i_target = label2block[lbl];
assert(instr->i_target != NULL);
assert(instr->i_target->b_label == lbl);
assert(instr->i_target->b_label.id == lbl);
}
}
}
Expand Down Expand Up @@ -9857,10 +9867,10 @@ instructions_to_cfg(PyObject *instructions, cfg_builder *g)
}
RETURN_IF_ERROR(cfg_builder_addop(g, opcode, oparg, loc));
}
if (translate_jump_labels_to_targets(g->g_entryblock) < 0) {
goto error;
struct cfg_instr *last = basicblock_last_instr(g->g_curblock);
if (last && !IS_TERMINATOR_OPCODE(last->i_opcode)) {
RETURN_IF_ERROR(cfg_builder_addop(g, RETURN_VALUE, 0, NO_LOCATION));
}

PyMem_Free(is_target);
return SUCCESS;
error:
Expand Down Expand Up @@ -9909,15 +9919,15 @@ cfg_to_instructions(cfg_builder *g)
}
int lbl = 0;
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
b->b_label = lbl;
b->b_label = (jump_target_label){lbl};
lbl += b->b_iused;
}
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
for (int i = 0; i < b->b_iused; i++) {
struct cfg_instr *instr = &b->b_instr[i];
location loc = instr->i_loc;
int arg = HAS_TARGET(instr->i_opcode) ?
instr->i_target->b_label : instr->i_oparg;
instr->i_target->b_label.id : instr->i_oparg;

PyObject *inst_tuple = Py_BuildValue(
"(iiiiii)", instr->i_opcode, arg,
Expand Down Expand Up @@ -9999,7 +10009,8 @@ _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts)
if (instructions_to_cfg(instructions, &g) < 0) {
goto error;
}
if (optimize_cfg(&g, consts, const_cache) < 0) {
int code_flags = 0, nlocals = 0, nparams = 0;
if (optimize_code_unit(&g, consts, const_cache, code_flags, nlocals, nparams) < 0) {
goto error;
}
res = cfg_to_instructions(&g);
Expand Down