Skip to content
Merged
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 26 additions & 31 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@
(opcode) == SETUP_WITH || \
(opcode) == SETUP_CLEANUP)

/* opcodes that must be last in the basicblock */
#define IS_TERMINTATOR_OPCODE(opcode) \
(IS_JUMP_OPCODE(opcode) || IS_SCOPE_EXIT_OPCODE(opcode))

/* opcodes which are not emitted in codegen stage, only by the assembler */
#define IS_ASSEMBLER_OPCODE(opcode) \
((opcode) == JUMP_FORWARD || \
Expand Down Expand Up @@ -262,27 +266,27 @@ typedef struct basicblock_ {


static struct instr *
basicblock_last_instr(basicblock *b) {
basicblock_last_instr(const basicblock *b) {
if (b->b_iused) {
return &b->b_instr[b->b_iused - 1];
}
return NULL;
}

static inline int
basicblock_returns(basicblock *b) {
basicblock_returns(const basicblock *b) {
struct instr *last = basicblock_last_instr(b);
return last && last->i_opcode == RETURN_VALUE;
}

static inline int
basicblock_exits_scope(basicblock *b) {
basicblock_exits_scope(const basicblock *b) {
struct instr *last = basicblock_last_instr(b);
return last && IS_SCOPE_EXIT_OPCODE(last->i_opcode);
}

static inline int
basicblock_nofallthrough(basicblock *b) {
basicblock_nofallthrough(const basicblock *b) {
struct instr *last = basicblock_last_instr(b);
return (last &&
(IS_SCOPE_EXIT_OPCODE(last->i_opcode) ||
Expand Down Expand Up @@ -1243,18 +1247,12 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
return stack_effect(opcode, oparg, -1);
}

static int
is_end_of_basic_block(struct instr *instr)
{
int opcode = instr->i_opcode;
return IS_JUMP_OPCODE(opcode) || IS_SCOPE_EXIT_OPCODE(opcode);
}

static int
compiler_use_new_implicit_block_if_needed(struct compiler *c)
{
basicblock *b = c->u->u_curblock;
if (b->b_iused && is_end_of_basic_block(basicblock_last_instr(b))) {
struct instr *last = basicblock_last_instr(b);
if (last && IS_TERMINTATOR_OPCODE(last->i_opcode)) {
basicblock *b = compiler_new_block(c);
if (b == NULL) {
return -1;
Expand Down Expand Up @@ -8553,18 +8551,6 @@ assemble(struct compiler *c, int addNone)
ADDOP(c, RETURN_VALUE);
}

for (basicblock *b = c->u->u_blocks; b != NULL; b = b->b_list) {
if (normalize_basic_block(b)) {
return NULL;
}
}

for (basicblock *b = c->u->u_blocks; b != NULL; b = b->b_list) {
if (extend_block(b)) {
return NULL;
}
}

assert(PyDict_GET_SIZE(c->u->u_varnames) < INT_MAX);
assert(PyDict_GET_SIZE(c->u->u_cellvars) < INT_MAX);
assert(PyDict_GET_SIZE(c->u->u_freevars) < INT_MAX);
Expand Down Expand Up @@ -8622,12 +8608,12 @@ assemble(struct compiler *c, int addNone)
if (optimize_cfg(entryblock, consts, c->c_const_cache)) {
goto error;
}
if (duplicate_exits_without_lineno(entryblock)) {
return NULL;
}
if (trim_unused_consts(entryblock, consts)) {
goto error;
}
if (duplicate_exits_without_lineno(entryblock)) {
return NULL;
}
propagate_line_numbers(entryblock);
guarantee_lineno_for_exits(entryblock, c->u->u_firstlineno);

Expand Down Expand Up @@ -9323,8 +9309,8 @@ clean_basic_block(basicblock *bb) {

static int
normalize_basic_block(basicblock *bb) {
/* Mark blocks as exit and/or nofallthrough.
Raise SystemError if CFG is malformed. */
/* Skip over empty blocks.
* Raise SystemError if jump or exit is not last instruction in the block. */
for (int i = 0; i < bb->b_iused; i++) {
int opcode = bb->b_instr[i].i_opcode;
assert(!IS_ASSEMBLER_OPCODE(opcode));
Expand Down Expand Up @@ -9461,15 +9447,24 @@ propagate_line_numbers(basicblock *entryblock) {
The consts object should still be in list form to allow new constants
to be appended.

All transformations keep the code size the same or smaller.
For those that reduce size, the gaps are initially filled with
Code trasnformations that reduce code size initially fill the gaps with
NOPs. Later those NOPs are removed.
*/

static int
optimize_cfg(basicblock *entryblock, PyObject *consts, PyObject *const_cache)
{
assert(PyDict_CheckExact(const_cache));
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
if (normalize_basic_block(b)) {
return -1;
}
}
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
if (extend_block(b)) {
return -1;
}
}
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
if (optimize_basic_block(const_cache, b, consts)) {
return -1;
Expand Down