bpo-42349: Compiler clean up. More yak-shaving for PEP 626. (GH-23267)
Make sure that CFG from compiler front-end is correct. Be a bit more aggressive in the compiler back-end.
This commit is contained in:
parent
fa96608513
commit
266b462238
|
@ -752,6 +752,30 @@ if 1:
|
||||||
self.assertEqual(None, opcodes[0].argval)
|
self.assertEqual(None, opcodes[0].argval)
|
||||||
self.assertEqual('RETURN_VALUE', opcodes[1].opname)
|
self.assertEqual('RETURN_VALUE', opcodes[1].opname)
|
||||||
|
|
||||||
|
def test_consts_in_conditionals(self):
|
||||||
|
def and_true(x):
|
||||||
|
return True and x
|
||||||
|
|
||||||
|
def and_false(x):
|
||||||
|
return False and x
|
||||||
|
|
||||||
|
def or_true(x):
|
||||||
|
return True or x
|
||||||
|
|
||||||
|
def or_false(x):
|
||||||
|
return False or x
|
||||||
|
|
||||||
|
funcs = [and_true, and_false, or_true, or_false]
|
||||||
|
|
||||||
|
# Check that condition is removed.
|
||||||
|
for func in funcs:
|
||||||
|
with self.subTest(func=func):
|
||||||
|
opcodes = list(dis.get_instructions(func))
|
||||||
|
self.assertEqual(2, len(opcodes))
|
||||||
|
self.assertIn('LOAD_', opcodes[0].opname)
|
||||||
|
self.assertEqual('RETURN_VALUE', opcodes[1].opname)
|
||||||
|
|
||||||
|
|
||||||
def test_big_dict_literal(self):
|
def test_big_dict_literal(self):
|
||||||
# The compiler has a flushing point in "compiler_dict" that calls compiles
|
# The compiler has a flushing point in "compiler_dict" that calls compiles
|
||||||
# a portion of the dictionary literal when the loop that iterates over the items
|
# a portion of the dictionary literal when the loop that iterates over the items
|
||||||
|
|
|
@ -145,30 +145,24 @@ def bug1333982(x=[]):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
dis_bug1333982 = """\
|
dis_bug1333982 = """\
|
||||||
%3d 0 LOAD_CONST 1 (0)
|
%3d 0 LOAD_ASSERTION_ERROR
|
||||||
2 POP_JUMP_IF_TRUE 26
|
2 LOAD_CONST 2 (<code object <listcomp> at 0x..., file "%s", line %d>)
|
||||||
4 LOAD_ASSERTION_ERROR
|
4 LOAD_CONST 3 ('bug1333982.<locals>.<listcomp>')
|
||||||
6 LOAD_CONST 2 (<code object <listcomp> at 0x..., file "%s", line %d>)
|
6 MAKE_FUNCTION 0
|
||||||
8 LOAD_CONST 3 ('bug1333982.<locals>.<listcomp>')
|
8 LOAD_FAST 0 (x)
|
||||||
10 MAKE_FUNCTION 0
|
10 GET_ITER
|
||||||
12 LOAD_FAST 0 (x)
|
12 CALL_FUNCTION 1
|
||||||
14 GET_ITER
|
|
||||||
16 CALL_FUNCTION 1
|
|
||||||
|
|
||||||
%3d 18 LOAD_CONST 4 (1)
|
%3d 14 LOAD_CONST 4 (1)
|
||||||
|
|
||||||
%3d 20 BINARY_ADD
|
%3d 16 BINARY_ADD
|
||||||
22 CALL_FUNCTION 1
|
18 CALL_FUNCTION 1
|
||||||
24 RAISE_VARARGS 1
|
20 RAISE_VARARGS 1
|
||||||
|
|
||||||
%3d >> 26 LOAD_CONST 0 (None)
|
|
||||||
28 RETURN_VALUE
|
|
||||||
""" % (bug1333982.__code__.co_firstlineno + 1,
|
""" % (bug1333982.__code__.co_firstlineno + 1,
|
||||||
__file__,
|
__file__,
|
||||||
bug1333982.__code__.co_firstlineno + 1,
|
bug1333982.__code__.co_firstlineno + 1,
|
||||||
bug1333982.__code__.co_firstlineno + 2,
|
bug1333982.__code__.co_firstlineno + 2,
|
||||||
bug1333982.__code__.co_firstlineno + 1,
|
bug1333982.__code__.co_firstlineno + 1)
|
||||||
bug1333982.__code__.co_firstlineno + 3)
|
|
||||||
|
|
||||||
_BIG_LINENO_FORMAT = """\
|
_BIG_LINENO_FORMAT = """\
|
||||||
%3d 0 LOAD_GLOBAL 0 (spam)
|
%3d 0 LOAD_GLOBAL 0 (spam)
|
||||||
|
@ -674,8 +668,15 @@ class DisWithFileTests(DisTests):
|
||||||
return output.getvalue()
|
return output.getvalue()
|
||||||
|
|
||||||
|
|
||||||
|
if sys.flags.optimize:
|
||||||
|
code_info_consts = "0: None"
|
||||||
|
else:
|
||||||
|
code_info_consts = (
|
||||||
|
"""0: 'Formatted details of methods, functions, or code.'
|
||||||
|
1: None"""
|
||||||
|
)
|
||||||
|
|
||||||
code_info_code_info = """\
|
code_info_code_info = f"""\
|
||||||
Name: code_info
|
Name: code_info
|
||||||
Filename: (.*)
|
Filename: (.*)
|
||||||
Argument count: 1
|
Argument count: 1
|
||||||
|
@ -685,13 +686,13 @@ Number of locals: 1
|
||||||
Stack size: 3
|
Stack size: 3
|
||||||
Flags: OPTIMIZED, NEWLOCALS, NOFREE
|
Flags: OPTIMIZED, NEWLOCALS, NOFREE
|
||||||
Constants:
|
Constants:
|
||||||
0: %r
|
{code_info_consts}
|
||||||
Names:
|
Names:
|
||||||
0: _format_code_info
|
0: _format_code_info
|
||||||
1: _get_code_object
|
1: _get_code_object
|
||||||
Variable names:
|
Variable names:
|
||||||
0: x""" % (('Formatted details of methods, functions, or code.',)
|
0: x"""
|
||||||
if sys.flags.optimize < 2 else (None,))
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def tricky(a, b, /, x, y, z=True, *args, c, d, e=[], **kwds):
|
def tricky(a, b, /, x, y, z=True, *args, c, d, e=[], **kwds):
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Make sure that the compiler front-end produces a well-formed control flow graph. Be be more aggressive in the compiler back-end, as it is now safe to do so.
|
191
Python/compile.c
191
Python/compile.c
|
@ -2587,6 +2587,7 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond)
|
||||||
VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n));
|
VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n));
|
||||||
ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, n));
|
ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, n));
|
||||||
ADDOP_JUMP(c, cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next);
|
ADDOP_JUMP(c, cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next);
|
||||||
|
NEXT_BLOCK(c);
|
||||||
basicblock *end = compiler_new_block(c);
|
basicblock *end = compiler_new_block(c);
|
||||||
if (end == NULL)
|
if (end == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2610,6 +2611,7 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond)
|
||||||
/* general implementation */
|
/* general implementation */
|
||||||
VISIT(c, expr, e);
|
VISIT(c, expr, e);
|
||||||
ADDOP_JUMP(c, cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next);
|
ADDOP_JUMP(c, cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next);
|
||||||
|
NEXT_BLOCK(c);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2829,7 +2831,7 @@ compiler_async_for(struct compiler *c, stmt_ty s)
|
||||||
static int
|
static int
|
||||||
compiler_while(struct compiler *c, stmt_ty s)
|
compiler_while(struct compiler *c, stmt_ty s)
|
||||||
{
|
{
|
||||||
basicblock *loop, *orelse, *end, *anchor = NULL;
|
basicblock *loop, *body, *end, *anchor = NULL;
|
||||||
int constant = expr_constant(s->v.While.test);
|
int constant = expr_constant(s->v.While.test);
|
||||||
|
|
||||||
if (constant == 0) {
|
if (constant == 0) {
|
||||||
|
@ -2850,42 +2852,32 @@ compiler_while(struct compiler *c, stmt_ty s)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
loop = compiler_new_block(c);
|
loop = compiler_new_block(c);
|
||||||
|
body = compiler_new_block(c);
|
||||||
|
anchor = compiler_new_block(c);
|
||||||
end = compiler_new_block(c);
|
end = compiler_new_block(c);
|
||||||
if (constant == -1) {
|
if (loop == NULL || body == NULL || anchor == NULL || end == NULL) {
|
||||||
anchor = compiler_new_block(c);
|
|
||||||
if (anchor == NULL)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (loop == NULL || end == NULL)
|
|
||||||
return 0;
|
return 0;
|
||||||
if (s->v.While.orelse) {
|
|
||||||
orelse = compiler_new_block(c);
|
|
||||||
if (orelse == NULL)
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
orelse = NULL;
|
|
||||||
|
|
||||||
compiler_use_next_block(c, loop);
|
compiler_use_next_block(c, loop);
|
||||||
if (!compiler_push_fblock(c, WHILE_LOOP, loop, end, NULL))
|
if (!compiler_push_fblock(c, WHILE_LOOP, loop, end, NULL)) {
|
||||||
return 0;
|
return 0;
|
||||||
if (constant == -1) {
|
|
||||||
if (!compiler_jump_if(c, s->v.While.test, anchor, 0))
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
if (constant == -1) {
|
||||||
|
if (!compiler_jump_if(c, s->v.While.test, anchor, 0)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compiler_use_next_block(c, body);
|
||||||
VISIT_SEQ(c, stmt, s->v.While.body);
|
VISIT_SEQ(c, stmt, s->v.While.body);
|
||||||
ADDOP_JUMP(c, JUMP_ABSOLUTE, loop);
|
ADDOP_JUMP(c, JUMP_ABSOLUTE, loop);
|
||||||
|
|
||||||
/* XXX should the two POP instructions be in a separate block
|
|
||||||
if there is no else clause ?
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (constant == -1)
|
|
||||||
compiler_use_next_block(c, anchor);
|
|
||||||
compiler_pop_fblock(c, WHILE_LOOP, loop);
|
compiler_pop_fblock(c, WHILE_LOOP, loop);
|
||||||
|
|
||||||
if (orelse != NULL) /* what if orelse is just pass? */
|
compiler_use_next_block(c, anchor);
|
||||||
|
if (s->v.While.orelse) {
|
||||||
VISIT_SEQ(c, stmt, s->v.While.orelse);
|
VISIT_SEQ(c, stmt, s->v.While.orelse);
|
||||||
|
}
|
||||||
compiler_use_next_block(c, end);
|
compiler_use_next_block(c, end);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -2916,6 +2908,7 @@ compiler_return(struct compiler *c, stmt_ty s)
|
||||||
VISIT(c, expr, s->v.Return.value);
|
VISIT(c, expr, s->v.Return.value);
|
||||||
}
|
}
|
||||||
ADDOP(c, RETURN_VALUE);
|
ADDOP(c, RETURN_VALUE);
|
||||||
|
NEXT_BLOCK(c);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -2934,6 +2927,7 @@ compiler_break(struct compiler *c)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ADDOP_JUMP(c, JUMP_ABSOLUTE, loop->fb_exit);
|
ADDOP_JUMP(c, JUMP_ABSOLUTE, loop->fb_exit);
|
||||||
|
NEXT_BLOCK(c);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2948,6 +2942,7 @@ compiler_continue(struct compiler *c)
|
||||||
return compiler_error(c, "'continue' not properly in loop");
|
return compiler_error(c, "'continue' not properly in loop");
|
||||||
}
|
}
|
||||||
ADDOP_JUMP(c, JUMP_ABSOLUTE, loop->fb_block);
|
ADDOP_JUMP(c, JUMP_ABSOLUTE, loop->fb_block);
|
||||||
|
NEXT_BLOCK(c)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3087,6 +3082,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
|
||||||
ADDOP(c, DUP_TOP);
|
ADDOP(c, DUP_TOP);
|
||||||
VISIT(c, expr, handler->v.ExceptHandler.type);
|
VISIT(c, expr, handler->v.ExceptHandler.type);
|
||||||
ADDOP_JUMP(c, JUMP_IF_NOT_EXC_MATCH, except);
|
ADDOP_JUMP(c, JUMP_IF_NOT_EXC_MATCH, except);
|
||||||
|
NEXT_BLOCK(c);
|
||||||
}
|
}
|
||||||
ADDOP(c, POP_TOP);
|
ADDOP(c, POP_TOP);
|
||||||
if (handler->v.ExceptHandler.name) {
|
if (handler->v.ExceptHandler.name) {
|
||||||
|
@ -3427,6 +3423,7 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ADDOP_I(c, RAISE_VARARGS, (int)n);
|
ADDOP_I(c, RAISE_VARARGS, (int)n);
|
||||||
|
NEXT_BLOCK(c);
|
||||||
break;
|
break;
|
||||||
case Try_kind:
|
case Try_kind:
|
||||||
return compiler_try(c, s);
|
return compiler_try(c, s);
|
||||||
|
@ -4798,6 +4795,7 @@ compiler_with_except_finish(struct compiler *c) {
|
||||||
if (exit == NULL)
|
if (exit == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
ADDOP_JUMP(c, POP_JUMP_IF_TRUE, exit);
|
ADDOP_JUMP(c, POP_JUMP_IF_TRUE, exit);
|
||||||
|
NEXT_BLOCK(c);
|
||||||
ADDOP(c, RERAISE);
|
ADDOP(c, RERAISE);
|
||||||
compiler_use_next_block(c, exit);
|
compiler_use_next_block(c, exit);
|
||||||
ADDOP(c, POP_TOP);
|
ADDOP(c, POP_TOP);
|
||||||
|
@ -5521,6 +5519,7 @@ stackdepth(struct compiler *c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (next != NULL) {
|
if (next != NULL) {
|
||||||
|
assert(b->b_nofallthrough == 0);
|
||||||
stackdepth_push(&sp, next, depth);
|
stackdepth_push(&sp, next, depth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6096,7 +6095,6 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
|
||||||
struct instr nop;
|
struct instr nop;
|
||||||
nop.i_opcode = NOP;
|
nop.i_opcode = NOP;
|
||||||
struct instr *target;
|
struct instr *target;
|
||||||
int lineno;
|
|
||||||
for (int i = 0; i < bb->b_iused; i++) {
|
for (int i = 0; i < bb->b_iused; i++) {
|
||||||
struct instr *inst = &bb->b_instr[i];
|
struct instr *inst = &bb->b_instr[i];
|
||||||
int oparg = inst->i_oparg;
|
int oparg = inst->i_oparg;
|
||||||
|
@ -6112,23 +6110,50 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
|
||||||
target = &nop;
|
target = &nop;
|
||||||
}
|
}
|
||||||
switch (inst->i_opcode) {
|
switch (inst->i_opcode) {
|
||||||
/* Skip over LOAD_CONST trueconst
|
/* Remove LOAD_CONST const; conditional jump */
|
||||||
POP_JUMP_IF_FALSE xx. This improves
|
|
||||||
"while 1" performance. */
|
|
||||||
case LOAD_CONST:
|
case LOAD_CONST:
|
||||||
if (nextop != POP_JUMP_IF_FALSE) {
|
{
|
||||||
break;
|
PyObject* cnt;
|
||||||
}
|
int is_true;
|
||||||
PyObject* cnt = PyList_GET_ITEM(consts, oparg);
|
int jump_if_true;
|
||||||
int is_true = PyObject_IsTrue(cnt);
|
switch(nextop) {
|
||||||
if (is_true == -1) {
|
case POP_JUMP_IF_FALSE:
|
||||||
goto error;
|
case POP_JUMP_IF_TRUE:
|
||||||
}
|
cnt = PyList_GET_ITEM(consts, oparg);
|
||||||
if (is_true == 1) {
|
is_true = PyObject_IsTrue(cnt);
|
||||||
inst->i_opcode = NOP;
|
if (is_true == -1) {
|
||||||
bb->b_instr[i+1].i_opcode = NOP;
|
goto error;
|
||||||
|
}
|
||||||
|
inst->i_opcode = NOP;
|
||||||
|
jump_if_true = nextop == POP_JUMP_IF_TRUE;
|
||||||
|
if (is_true == jump_if_true) {
|
||||||
|
bb->b_instr[i+1].i_opcode = JUMP_ABSOLUTE;
|
||||||
|
bb->b_nofallthrough = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bb->b_instr[i+1].i_opcode = NOP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JUMP_IF_FALSE_OR_POP:
|
||||||
|
case JUMP_IF_TRUE_OR_POP:
|
||||||
|
cnt = PyList_GET_ITEM(consts, oparg);
|
||||||
|
is_true = PyObject_IsTrue(cnt);
|
||||||
|
if (is_true == -1) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
jump_if_true = nextop == JUMP_IF_TRUE_OR_POP;
|
||||||
|
if (is_true == jump_if_true) {
|
||||||
|
bb->b_instr[i+1].i_opcode = JUMP_ABSOLUTE;
|
||||||
|
bb->b_nofallthrough = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
inst->i_opcode = NOP;
|
||||||
|
bb->b_instr[i+1].i_opcode = NOP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Try to fold tuples of constants.
|
/* Try to fold tuples of constants.
|
||||||
Skip over BUILD_SEQN 1 UNPACK_SEQN 1.
|
Skip over BUILD_SEQN 1 UNPACK_SEQN 1.
|
||||||
|
@ -6176,16 +6201,21 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
|
||||||
switch(target->i_opcode) {
|
switch(target->i_opcode) {
|
||||||
case POP_JUMP_IF_FALSE:
|
case POP_JUMP_IF_FALSE:
|
||||||
*inst = *target;
|
*inst = *target;
|
||||||
|
--i;
|
||||||
break;
|
break;
|
||||||
case JUMP_ABSOLUTE:
|
case JUMP_ABSOLUTE:
|
||||||
case JUMP_FORWARD:
|
case JUMP_FORWARD:
|
||||||
case JUMP_IF_FALSE_OR_POP:
|
case JUMP_IF_FALSE_OR_POP:
|
||||||
inst->i_target = target->i_target;
|
if (inst->i_target != target->i_target) {
|
||||||
|
inst->i_target = target->i_target;
|
||||||
|
--i;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case JUMP_IF_TRUE_OR_POP:
|
case JUMP_IF_TRUE_OR_POP:
|
||||||
assert (inst->i_target->b_iused == 1);
|
assert (inst->i_target->b_iused == 1);
|
||||||
inst->i_opcode = POP_JUMP_IF_FALSE;
|
inst->i_opcode = POP_JUMP_IF_FALSE;
|
||||||
inst->i_target = inst->i_target->b_next;
|
inst->i_target = inst->i_target->b_next;
|
||||||
|
--i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -6194,16 +6224,21 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
|
||||||
switch(target->i_opcode) {
|
switch(target->i_opcode) {
|
||||||
case POP_JUMP_IF_TRUE:
|
case POP_JUMP_IF_TRUE:
|
||||||
*inst = *target;
|
*inst = *target;
|
||||||
|
--i;
|
||||||
break;
|
break;
|
||||||
case JUMP_ABSOLUTE:
|
case JUMP_ABSOLUTE:
|
||||||
case JUMP_FORWARD:
|
case JUMP_FORWARD:
|
||||||
case JUMP_IF_TRUE_OR_POP:
|
case JUMP_IF_TRUE_OR_POP:
|
||||||
inst->i_target = target->i_target;
|
if (inst->i_target != target->i_target) {
|
||||||
|
inst->i_target = target->i_target;
|
||||||
|
--i;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case JUMP_IF_FALSE_OR_POP:
|
case JUMP_IF_FALSE_OR_POP:
|
||||||
assert (inst->i_target->b_iused == 1);
|
assert (inst->i_target->b_iused == 1);
|
||||||
inst->i_opcode = POP_JUMP_IF_TRUE;
|
inst->i_opcode = POP_JUMP_IF_TRUE;
|
||||||
inst->i_target = inst->i_target->b_next;
|
inst->i_target = inst->i_target->b_next;
|
||||||
|
--i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -6212,7 +6247,10 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
|
||||||
switch(target->i_opcode) {
|
switch(target->i_opcode) {
|
||||||
case JUMP_ABSOLUTE:
|
case JUMP_ABSOLUTE:
|
||||||
case JUMP_FORWARD:
|
case JUMP_FORWARD:
|
||||||
inst->i_target = target->i_target;
|
if (inst->i_target != target->i_target) {
|
||||||
|
inst->i_target = target->i_target;
|
||||||
|
--i;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -6221,7 +6259,10 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
|
||||||
switch(target->i_opcode) {
|
switch(target->i_opcode) {
|
||||||
case JUMP_ABSOLUTE:
|
case JUMP_ABSOLUTE:
|
||||||
case JUMP_FORWARD:
|
case JUMP_FORWARD:
|
||||||
inst->i_target = target->i_target;
|
if (inst->i_target != target->i_target) {
|
||||||
|
inst->i_target = target->i_target;
|
||||||
|
--i;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -6231,12 +6272,17 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
|
||||||
assert (i == bb->b_iused-1);
|
assert (i == bb->b_iused-1);
|
||||||
switch(target->i_opcode) {
|
switch(target->i_opcode) {
|
||||||
case JUMP_FORWARD:
|
case JUMP_FORWARD:
|
||||||
inst->i_target = target->i_target;
|
if (inst->i_target != target->i_target) {
|
||||||
|
inst->i_target = target->i_target;
|
||||||
|
--i;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case JUMP_ABSOLUTE:
|
case JUMP_ABSOLUTE:
|
||||||
lineno = inst->i_lineno;
|
if (inst->i_target != target->i_target) {
|
||||||
*inst = *target;
|
inst->i_target = target->i_target;
|
||||||
inst->i_lineno = lineno;
|
inst->i_opcode = target->i_opcode;
|
||||||
|
--i;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (inst->i_target->b_exit && inst->i_target->b_iused <= MAX_COPY_SIZE) {
|
if (inst->i_target->b_exit && inst->i_target->b_iused <= MAX_COPY_SIZE) {
|
||||||
|
@ -6268,15 +6314,15 @@ clean_basic_block(basicblock *bb) {
|
||||||
for (int src = 0; src < bb->b_iused; src++) {
|
for (int src = 0; src < bb->b_iused; src++) {
|
||||||
int lineno = bb->b_instr[src].i_lineno;
|
int lineno = bb->b_instr[src].i_lineno;
|
||||||
if (bb->b_instr[src].i_opcode == NOP) {
|
if (bb->b_instr[src].i_opcode == NOP) {
|
||||||
/* Eliminate no-op if it doesn't have a line number, or
|
/* Eliminate no-op if it doesn't have a line number */
|
||||||
* if the next instruction has same line number or no line number, or
|
|
||||||
* if the previous instruction had the same line number. */
|
|
||||||
if (lineno < 0) {
|
if (lineno < 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
/* or, if the previous instruction had the same line number. */
|
||||||
if (prev_lineno == lineno) {
|
if (prev_lineno == lineno) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
/* or, if the next instruction has same line number or no line number */
|
||||||
if (src < bb->b_iused - 1) {
|
if (src < bb->b_iused - 1) {
|
||||||
int next_lineno = bb->b_instr[src+1].i_lineno;
|
int next_lineno = bb->b_instr[src+1].i_lineno;
|
||||||
if (next_lineno < 0 || next_lineno == lineno) {
|
if (next_lineno < 0 || next_lineno == lineno) {
|
||||||
|
@ -6284,6 +6330,19 @@ clean_basic_block(basicblock *bb) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
basicblock* next = bb->b_next;
|
||||||
|
while (next && next->b_iused == 0) {
|
||||||
|
next = next->b_next;
|
||||||
|
}
|
||||||
|
/* or if last instruction in BB and next BB has same line number */
|
||||||
|
if (next) {
|
||||||
|
if (lineno == next->b_instr[0].i_lineno) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (dest != src) {
|
if (dest != src) {
|
||||||
bb->b_instr[dest] = bb->b_instr[src];
|
bb->b_instr[dest] = bb->b_instr[src];
|
||||||
|
@ -6295,30 +6354,36 @@ clean_basic_block(basicblock *bb) {
|
||||||
bb->b_iused = dest;
|
bb->b_iused = dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
normalise_basic_block(basicblock *bb) {
|
static int
|
||||||
/* Remove any code following a return or re-raise,
|
normalize_basic_block(basicblock *bb) {
|
||||||
and mark those blocks as exit and/or nofallthrough. */
|
/* Mark blocks as exit and/or nofallthrough.
|
||||||
|
Raise SystemError if CFG is malformed. */
|
||||||
for (int i = 0; i < bb->b_iused; i++) {
|
for (int i = 0; i < bb->b_iused; i++) {
|
||||||
switch(bb->b_instr[i].i_opcode) {
|
switch(bb->b_instr[i].i_opcode) {
|
||||||
case RETURN_VALUE:
|
case RETURN_VALUE:
|
||||||
case RAISE_VARARGS:
|
case RAISE_VARARGS:
|
||||||
case RERAISE:
|
case RERAISE:
|
||||||
bb->b_iused = i+1;
|
|
||||||
bb->b_exit = 1;
|
bb->b_exit = 1;
|
||||||
bb->b_nofallthrough = 1;
|
/* fall through */
|
||||||
return;
|
|
||||||
case JUMP_ABSOLUTE:
|
case JUMP_ABSOLUTE:
|
||||||
case JUMP_FORWARD:
|
case JUMP_FORWARD:
|
||||||
bb->b_iused = i+1;
|
|
||||||
bb->b_nofallthrough = 1;
|
bb->b_nofallthrough = 1;
|
||||||
return;
|
/* fall through */
|
||||||
|
case POP_JUMP_IF_FALSE:
|
||||||
|
case POP_JUMP_IF_TRUE:
|
||||||
|
case JUMP_IF_FALSE_OR_POP:
|
||||||
|
case JUMP_IF_TRUE_OR_POP:
|
||||||
|
if (i != bb->b_iused-1) {
|
||||||
|
PyErr_SetString(PyExc_SystemError, "malformed control flow graph.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mark_reachable(struct assembler *a) {
|
mark_reachable(struct assembler *a) {
|
||||||
basicblock **stack, **sp;
|
basicblock **stack, **sp;
|
||||||
|
@ -6363,7 +6428,9 @@ static int
|
||||||
optimize_cfg(struct assembler *a, PyObject *consts)
|
optimize_cfg(struct assembler *a, PyObject *consts)
|
||||||
{
|
{
|
||||||
for (basicblock *b = a->a_entry; b != NULL; b = b->b_next) {
|
for (basicblock *b = a->a_entry; b != NULL; b = b->b_next) {
|
||||||
normalise_basic_block(b);
|
if (normalize_basic_block(b)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (basicblock *b = a->a_entry; b != NULL; b = b->b_next) {
|
for (basicblock *b = a->a_entry; b != NULL; b = b->b_next) {
|
||||||
if (optimize_basic_block(b, consts)) {
|
if (optimize_basic_block(b, consts)) {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue