gh-92782: unify the style of CFG traversal algorithms in the compiler (GH-92784)
This commit is contained in:
parent
93fc14933b
commit
8781a041a0
@ -7061,7 +7061,6 @@ struct assembler {
|
|||||||
PyObject *a_except_table; /* bytes containing exception table */
|
PyObject *a_except_table; /* bytes containing exception table */
|
||||||
basicblock *a_entry;
|
basicblock *a_entry;
|
||||||
int a_offset; /* offset into bytecode */
|
int a_offset; /* offset into bytecode */
|
||||||
int a_nblocks; /* number of reachable blocks */
|
|
||||||
int a_except_table_off; /* offset into exception table */
|
int a_except_table_off; /* offset into exception table */
|
||||||
int a_prevlineno; /* lineno of last emitted line in line table */
|
int a_prevlineno; /* lineno of last emitted line in line table */
|
||||||
int a_prev_end_lineno; /* end_lineno of last emitted line in line table */
|
int a_prev_end_lineno; /* end_lineno of last emitted line in line table */
|
||||||
@ -7074,6 +7073,20 @@ struct assembler {
|
|||||||
int a_location_off; /* offset of last written location info frame */
|
int a_location_off; /* offset of last written location info frame */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static basicblock**
|
||||||
|
make_cfg_traversal_stack(basicblock *entry) {
|
||||||
|
int nblocks = 0;
|
||||||
|
for (basicblock *b = entry; b != NULL; b = b->b_next) {
|
||||||
|
b->b_visited = 0;
|
||||||
|
nblocks++;
|
||||||
|
}
|
||||||
|
basicblock **stack = (basicblock **)PyMem_Malloc(sizeof(basicblock *) * nblocks);
|
||||||
|
if (!stack) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
}
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
Py_LOCAL_INLINE(void)
|
Py_LOCAL_INLINE(void)
|
||||||
stackdepth_push(basicblock ***sp, basicblock *b, int depth)
|
stackdepth_push(basicblock ***sp, basicblock *b, int depth)
|
||||||
{
|
{
|
||||||
@ -7089,31 +7102,26 @@ stackdepth_push(basicblock ***sp, basicblock *b, int depth)
|
|||||||
* cycles in the flow graph have no net effect on the stack depth.
|
* cycles in the flow graph have no net effect on the stack depth.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
stackdepth(struct compiler *c)
|
stackdepth(struct compiler *c, basicblock *entry)
|
||||||
{
|
{
|
||||||
basicblock *b, *entryblock = NULL;
|
for (basicblock *b = entry; b != NULL; b = b->b_next) {
|
||||||
basicblock **stack, **sp;
|
|
||||||
int nblocks = 0, maxdepth = 0;
|
|
||||||
for (b = c->u->u_blocks; b != NULL; b = b->b_list) {
|
|
||||||
b->b_startdepth = INT_MIN;
|
b->b_startdepth = INT_MIN;
|
||||||
entryblock = b;
|
|
||||||
nblocks++;
|
|
||||||
}
|
}
|
||||||
assert(entryblock!= NULL);
|
basicblock **stack = make_cfg_traversal_stack(entry);
|
||||||
stack = (basicblock **)PyObject_Malloc(sizeof(basicblock *) * nblocks);
|
|
||||||
if (!stack) {
|
if (!stack) {
|
||||||
PyErr_NoMemory();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sp = stack;
|
int maxdepth = 0;
|
||||||
|
basicblock **sp = stack;
|
||||||
if (c->u->u_ste->ste_generator || c->u->u_ste->ste_coroutine) {
|
if (c->u->u_ste->ste_generator || c->u->u_ste->ste_coroutine) {
|
||||||
stackdepth_push(&sp, entryblock, 1);
|
stackdepth_push(&sp, entry, 1);
|
||||||
} else {
|
} else {
|
||||||
stackdepth_push(&sp, entryblock, 0);
|
stackdepth_push(&sp, entry, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (sp != stack) {
|
while (sp != stack) {
|
||||||
b = *--sp;
|
basicblock *b = *--sp;
|
||||||
int depth = b->b_startdepth;
|
int depth = b->b_startdepth;
|
||||||
assert(depth >= 0);
|
assert(depth >= 0);
|
||||||
basicblock *next = b->b_next;
|
basicblock *next = b->b_next;
|
||||||
@ -7159,7 +7167,7 @@ stackdepth(struct compiler *c)
|
|||||||
stackdepth_push(&sp, next, depth);
|
stackdepth_push(&sp, next, depth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PyObject_Free(stack);
|
PyMem_Free(stack);
|
||||||
return maxdepth;
|
return maxdepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7264,14 +7272,8 @@ copy_except_stack(ExceptStack *stack) {
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
label_exception_targets(basicblock *entry) {
|
label_exception_targets(basicblock *entry) {
|
||||||
int nblocks = 0;
|
basicblock **todo_stack = make_cfg_traversal_stack(entry);
|
||||||
for (basicblock *b = entry; b != NULL; b = b->b_next) {
|
|
||||||
b->b_visited = 0;
|
|
||||||
nblocks++;
|
|
||||||
}
|
|
||||||
basicblock **todo_stack = PyMem_Malloc(sizeof(basicblock *)*nblocks);
|
|
||||||
if (todo_stack == NULL) {
|
if (todo_stack == NULL) {
|
||||||
PyErr_NoMemory();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ExceptStack *except_stack = make_except_stack();
|
ExceptStack *except_stack = make_except_stack();
|
||||||
@ -8051,7 +8053,7 @@ static int
|
|||||||
optimize_cfg(struct compiler *c, struct assembler *a, PyObject *consts);
|
optimize_cfg(struct compiler *c, struct assembler *a, PyObject *consts);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
trim_unused_consts(struct compiler *c, struct assembler *a, PyObject *consts);
|
trim_unused_consts(struct assembler *a, PyObject *consts);
|
||||||
|
|
||||||
/* Duplicates exit BBs, so that line numbers can be propagated to them */
|
/* Duplicates exit BBs, so that line numbers can be propagated to them */
|
||||||
static int
|
static int
|
||||||
@ -8347,7 +8349,6 @@ assemble(struct compiler *c, int addNone)
|
|||||||
if (!assemble_init(&a, nblocks, c->u->u_firstlineno))
|
if (!assemble_init(&a, nblocks, c->u->u_firstlineno))
|
||||||
goto error;
|
goto error;
|
||||||
a.a_entry = entryblock;
|
a.a_entry = entryblock;
|
||||||
a.a_nblocks = nblocks;
|
|
||||||
|
|
||||||
int numdropped = fix_cell_offsets(c, entryblock, cellfixedoffsets);
|
int numdropped = fix_cell_offsets(c, entryblock, cellfixedoffsets);
|
||||||
PyMem_Free(cellfixedoffsets); // At this point we're done with it.
|
PyMem_Free(cellfixedoffsets); // At this point we're done with it.
|
||||||
@ -8368,12 +8369,12 @@ assemble(struct compiler *c, int addNone)
|
|||||||
if (duplicate_exits_without_lineno(c)) {
|
if (duplicate_exits_without_lineno(c)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (trim_unused_consts(c, &a, consts)) {
|
if (trim_unused_consts(&a, consts)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
propagate_line_numbers(&a);
|
propagate_line_numbers(&a);
|
||||||
guarantee_lineno_for_exits(&a, c->u->u_firstlineno);
|
guarantee_lineno_for_exits(&a, c->u->u_firstlineno);
|
||||||
int maxdepth = stackdepth(c);
|
int maxdepth = stackdepth(c, entryblock);
|
||||||
if (maxdepth < 0) {
|
if (maxdepth < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -9081,17 +9082,19 @@ normalize_basic_block(basicblock *bb) {
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
mark_reachable(struct assembler *a) {
|
mark_reachable(struct assembler *a) {
|
||||||
basicblock **stack, **sp;
|
basicblock **stack = make_cfg_traversal_stack(a->a_entry);
|
||||||
sp = stack = (basicblock **)PyObject_Malloc(sizeof(basicblock *) * a->a_nblocks);
|
|
||||||
if (stack == NULL) {
|
if (stack == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
basicblock **sp = stack;
|
||||||
a->a_entry->b_predecessors = 1;
|
a->a_entry->b_predecessors = 1;
|
||||||
*sp++ = a->a_entry;
|
*sp++ = a->a_entry;
|
||||||
while (sp > stack) {
|
while (sp > stack) {
|
||||||
basicblock *b = *(--sp);
|
basicblock *b = *(--sp);
|
||||||
|
b->b_visited = 1;
|
||||||
if (b->b_next && !b->b_nofallthrough) {
|
if (b->b_next && !b->b_nofallthrough) {
|
||||||
if (b->b_next->b_predecessors == 0) {
|
if (!b->b_next->b_visited) {
|
||||||
|
assert(b->b_next->b_predecessors == 0);
|
||||||
*sp++ = b->b_next;
|
*sp++ = b->b_next;
|
||||||
}
|
}
|
||||||
b->b_next->b_predecessors++;
|
b->b_next->b_predecessors++;
|
||||||
@ -9101,14 +9104,15 @@ mark_reachable(struct assembler *a) {
|
|||||||
struct instr *instr = &b->b_instr[i];
|
struct instr *instr = &b->b_instr[i];
|
||||||
if (is_jump(instr) || is_block_push(instr)) {
|
if (is_jump(instr) || is_block_push(instr)) {
|
||||||
target = instr->i_target;
|
target = instr->i_target;
|
||||||
if (target->b_predecessors == 0) {
|
if (!target->b_visited) {
|
||||||
|
assert(target->b_predecessors == 0 || target == b->b_next);
|
||||||
*sp++ = target;
|
*sp++ = target;
|
||||||
}
|
}
|
||||||
target->b_predecessors++;
|
target->b_predecessors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PyObject_Free(stack);
|
PyMem_Free(stack);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9128,12 +9132,15 @@ eliminate_empty_basic_blocks(basicblock *entry) {
|
|||||||
if (b->b_iused == 0) {
|
if (b->b_iused == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (is_jump(&b->b_instr[b->b_iused-1])) {
|
for (int i = 0; i < b->b_iused; i++) {
|
||||||
basicblock *target = b->b_instr[b->b_iused-1].i_target;
|
struct instr *instr = &b->b_instr[i];
|
||||||
while (target->b_iused == 0) {
|
if (is_jump(instr) || is_block_push(instr)) {
|
||||||
target = target->b_next;
|
basicblock *target = instr->i_target;
|
||||||
|
while (target->b_iused == 0) {
|
||||||
|
target = target->b_next;
|
||||||
|
}
|
||||||
|
instr->i_target = target;
|
||||||
}
|
}
|
||||||
b->b_instr[b->b_iused-1].i_target = target;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -9253,7 +9260,7 @@ optimize_cfg(struct compiler *c, struct assembler *a, PyObject *consts)
|
|||||||
|
|
||||||
// Remove trailing unused constants.
|
// Remove trailing unused constants.
|
||||||
static int
|
static int
|
||||||
trim_unused_consts(struct compiler *c, struct assembler *a, PyObject *consts)
|
trim_unused_consts(struct assembler *a, PyObject *consts)
|
||||||
{
|
{
|
||||||
assert(PyList_CheckExact(consts));
|
assert(PyList_CheckExact(consts));
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user