[Python-checkins] gh-87092: compiler's CFG construction moved to after codegen stage (#102320)
iritkatriel
webhook-mailer at python.org
Tue Mar 7 13:16:40 EST 2023
https://github.com/python/cpython/commit/54060ae91da2df44b3f6e6c698694d40284687e9
commit: 54060ae91da2df44b3f6e6c698694d40284687e9
branch: main
author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com>
committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com>
date: 2023-03-07T18:16:32Z
summary:
gh-87092: compiler's CFG construction moved to after codegen stage (#102320)
files:
M Python/compile.c
diff --git a/Python/compile.c b/Python/compile.c
index 2e60a8157533..45c97b4f8ef0 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -175,19 +175,18 @@ static struct jump_target_label_ NO_LABEL = {-1};
#define IS_LABEL(L) (!SAME_LABEL((L), (NO_LABEL)))
#define NEW_JUMP_TARGET_LABEL(C, NAME) \
- jump_target_label NAME = cfg_new_label(CFG_BUILDER(C)); \
+ jump_target_label NAME = instr_sequence_new_label(INSTR_SEQUENCE(C)); \
if (!IS_LABEL(NAME)) { \
return ERROR; \
}
#define USE_LABEL(C, LBL) \
- RETURN_IF_ERROR(cfg_builder_use_label(CFG_BUILDER(C), LBL))
+ RETURN_IF_ERROR(instr_sequence_use_label(INSTR_SEQUENCE(C), (LBL).id))
-struct instr {
+struct cfg_instr {
int i_opcode;
int i_oparg;
location i_loc;
- /* The following fields should not be set by the front-end: */
struct basicblock_ *i_target; /* target block (if jump instruction) */
struct basicblock_ *i_except; /* target block when exception is raised */
};
@@ -196,7 +195,7 @@ struct instr {
#define INSTR_SET_OP1(I, OP, ARG) \
do { \
assert(HAS_ARG(OP)); \
- struct instr *_instr__ptr_ = (I); \
+ struct cfg_instr *_instr__ptr_ = (I); \
_instr__ptr_->i_opcode = (OP); \
_instr__ptr_->i_oparg = (ARG); \
} while (0);
@@ -205,7 +204,7 @@ struct instr {
#define INSTR_SET_OP0(I, OP) \
do { \
assert(!HAS_ARG(OP)); \
- struct instr *_instr__ptr_ = (I); \
+ struct cfg_instr *_instr__ptr_ = (I); \
_instr__ptr_->i_opcode = (OP); \
_instr__ptr_->i_oparg = 0; \
} while (0);
@@ -235,25 +234,25 @@ is_bit_set_in_table(const uint32_t *table, int bitindex) {
}
static inline int
-is_relative_jump(struct instr *i)
+is_relative_jump(struct cfg_instr *i)
{
return is_bit_set_in_table(_PyOpcode_RelativeJump, i->i_opcode);
}
static inline int
-is_block_push(struct instr *i)
+is_block_push(struct cfg_instr *i)
{
return IS_BLOCK_PUSH_OPCODE(i->i_opcode);
}
static inline int
-is_jump(struct instr *i)
+is_jump(struct cfg_instr *i)
{
return IS_JUMP_OPCODE(i->i_opcode);
}
static int
-instr_size(struct instr *instruction)
+instr_size(struct cfg_instr *instruction)
{
int opcode = instruction->i_opcode;
assert(!IS_PSEUDO_OPCODE(opcode));
@@ -265,7 +264,7 @@ instr_size(struct instr *instruction)
}
static void
-write_instr(_Py_CODEUNIT *codestr, struct instr *instruction, int ilen)
+write_instr(_Py_CODEUNIT *codestr, struct cfg_instr *instruction, int ilen)
{
int opcode = instruction->i_opcode;
assert(!IS_PSEUDO_OPCODE(opcode));
@@ -313,7 +312,7 @@ typedef struct basicblock_ {
/* 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 */
- struct instr *b_instr;
+ struct cfg_instr *b_instr;
/* If b_next is non-NULL, it is a pointer to the next
block reached by normal control flow. */
struct basicblock_ *b_next;
@@ -342,7 +341,7 @@ typedef struct basicblock_ {
} basicblock;
-static struct instr *
+static struct cfg_instr *
basicblock_last_instr(const basicblock *b) {
assert(b->b_iused >= 0);
if (b->b_iused > 0) {
@@ -352,21 +351,15 @@ basicblock_last_instr(const basicblock *b) {
return NULL;
}
-static inline int
-basicblock_returns(const basicblock *b) {
- struct instr *last = basicblock_last_instr(b);
- return last && (last->i_opcode == RETURN_VALUE || last->i_opcode == RETURN_CONST);
-}
-
static inline int
basicblock_exits_scope(const basicblock *b) {
- struct instr *last = basicblock_last_instr(b);
+ struct cfg_instr *last = basicblock_last_instr(b);
return last && IS_SCOPE_EXIT_OPCODE(last->i_opcode);
}
static inline int
basicblock_nofallthrough(const basicblock *b) {
- struct instr *last = basicblock_last_instr(b);
+ struct cfg_instr *last = basicblock_last_instr(b);
return (last &&
(IS_SCOPE_EXIT_OPCODE(last->i_opcode) ||
IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)));
@@ -415,10 +408,208 @@ typedef struct cfg_builder_ {
basicblock *g_curblock;
/* label for the next instruction to be placed */
jump_target_label g_current_label;
- /* next free label id */
- int g_next_free_label;
} cfg_builder;
+typedef struct {
+ int i_opcode;
+ int i_oparg;
+ location i_loc;
+} instruction;
+
+
+typedef struct instr_sequence_ {
+ instruction *s_instrs;
+ int s_allocated;
+ int s_used;
+
+ int *s_labelmap; /* label id --> instr offset */
+ int s_labelmap_size;
+ int s_next_free_label; /* next free label id */
+} instr_sequence;
+
+#define INITIAL_INSTR_SEQUENCE_SIZE 100
+#define INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE 10
+
+/*
+ * Resize the array if index is out of range.
+ *
+ * idx: the index we want to access
+ * arr: pointer to the array
+ * alloc: pointer to the capacity of the array
+ * default_alloc: initial number of items
+ * item_size: size of each item
+ *
+ */
+static int
+ensure_array_large_enough(int idx, void **arr_, int *alloc, int default_alloc, size_t item_size)
+{
+ void *arr = *arr_;
+ if (arr == NULL) {
+ int new_alloc = default_alloc;
+ if (idx >= new_alloc) {
+ new_alloc = idx + default_alloc;
+ }
+ arr = PyObject_Calloc(new_alloc, item_size);
+ if (arr == NULL) {
+ PyErr_NoMemory();
+ return ERROR;
+ }
+ *alloc = new_alloc;
+ }
+ else if (idx >= *alloc) {
+ size_t oldsize = *alloc * item_size;
+ int new_alloc = *alloc << 1;
+ if (idx >= new_alloc) {
+ new_alloc = idx + default_alloc;
+ }
+ size_t newsize = new_alloc * item_size;
+
+ if (oldsize > (SIZE_MAX >> 1)) {
+ PyErr_NoMemory();
+ return ERROR;
+ }
+
+ assert(newsize > 0);
+ void *tmp = PyObject_Realloc(arr, newsize);
+ if (tmp == NULL) {
+ PyErr_NoMemory();
+ return ERROR;
+ }
+ *alloc = new_alloc;
+ arr = tmp;
+ memset((char *)arr + oldsize, 0, newsize - oldsize);
+ }
+
+ *arr_ = arr;
+ return SUCCESS;
+}
+
+static int
+instr_sequence_next_inst(instr_sequence *seq) {
+ assert(seq->s_instrs != NULL || seq->s_used == 0);
+
+ RETURN_IF_ERROR(
+ ensure_array_large_enough(seq->s_used + 1,
+ (void**)&seq->s_instrs,
+ &seq->s_allocated,
+ INITIAL_INSTR_SEQUENCE_SIZE,
+ sizeof(instruction)));
+ assert(seq->s_used < seq->s_allocated);
+ return seq->s_used++;
+}
+
+static jump_target_label
+instr_sequence_new_label(instr_sequence *seq)
+{
+ jump_target_label lbl = {seq->s_next_free_label++};
+ return lbl;
+}
+
+static int
+instr_sequence_use_label(instr_sequence *seq, int lbl) {
+ int old_size = seq->s_labelmap_size;
+ RETURN_IF_ERROR(
+ ensure_array_large_enough(lbl,
+ (void**)&seq->s_labelmap,
+ &seq->s_labelmap_size,
+ INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE,
+ sizeof(int)));
+
+ for(int i = old_size; i < seq->s_labelmap_size; i++) {
+ seq->s_labelmap[i] = -111; /* something weird, for debugging */
+ }
+ seq->s_labelmap[lbl] = seq->s_used; /* label refers to the next instruction */
+ return SUCCESS;
+}
+
+static int
+instr_sequence_addop(instr_sequence *seq, int opcode, int oparg, location loc)
+{
+ assert(IS_WITHIN_OPCODE_RANGE(opcode));
+ assert(!IS_ASSEMBLER_OPCODE(opcode));
+ assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0);
+ assert(0 <= oparg && oparg < (1 << 30));
+
+ int idx = instr_sequence_next_inst(seq);
+ RETURN_IF_ERROR(idx);
+ instruction *ci = &seq->s_instrs[idx];
+ ci->i_opcode = opcode;
+ ci->i_oparg = oparg;
+ ci->i_loc = loc;
+ return SUCCESS;
+}
+
+static int
+instr_sequence_insert_instruction(instr_sequence *seq, int pos,
+ int opcode, int oparg, location loc)
+{
+ assert(pos >= 0 && pos <= seq->s_used);
+ int last_idx = instr_sequence_next_inst(seq);
+ RETURN_IF_ERROR(last_idx);
+ for (int i=last_idx-1; i >= pos; i--) {
+ seq->s_instrs[i+1] = seq->s_instrs[i];
+ }
+ instruction *ci = &seq->s_instrs[pos];
+ ci->i_opcode = opcode;
+ ci->i_oparg = oparg;
+ ci->i_loc = loc;
+
+ /* fix the labels map */
+ for(int lbl=0; lbl < seq->s_labelmap_size; lbl++) {
+ if (seq->s_labelmap[lbl] >= pos) {
+ seq->s_labelmap[lbl]++;
+ }
+ }
+ return SUCCESS;
+}
+
+static void
+instr_sequence_fini(instr_sequence *seq) {
+ PyObject_Free(seq->s_labelmap);
+ seq->s_labelmap = NULL;
+
+ PyObject_Free(seq->s_instrs);
+ seq->s_instrs = NULL;
+}
+
+static int basicblock_addop(basicblock *b, int opcode, int oparg, location loc);
+static int cfg_builder_maybe_start_new_block(cfg_builder *g);
+
+static int
+cfg_builder_use_label(cfg_builder *g, jump_target_label lbl)
+{
+ g->g_current_label = lbl;
+ return cfg_builder_maybe_start_new_block(g);
+}
+
+static int
+cfg_builder_addop(cfg_builder *g, int opcode, int oparg, location loc)
+{
+ RETURN_IF_ERROR(cfg_builder_maybe_start_new_block(g));
+ return basicblock_addop(g->g_curblock, opcode, oparg, loc);
+}
+
+static int cfg_builder_init(cfg_builder *g);
+
+static int
+instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) {
+ memset(g, 0, sizeof(cfg_builder));
+ RETURN_IF_ERROR(cfg_builder_init(g));
+ /* Note: there can be more than one label for the same offset */
+ for (int i = 0; i < seq->s_used; i++) {
+ for (int j=0; j < seq->s_labelmap_size; j++) {
+ if (seq->s_labelmap[j] == i) {
+ jump_target_label lbl = {j};
+ RETURN_IF_ERROR(cfg_builder_use_label(g, lbl));
+ }
+ }
+ instruction *instr = &seq->s_instrs[i];
+ RETURN_IF_ERROR(cfg_builder_addop(g, instr->i_opcode, instr->i_oparg, instr->i_loc));
+ }
+ return SUCCESS;
+}
+
+
/* The following items change on entry and exit of code blocks.
They must be saved and restored when returning to a block.
*/
@@ -445,7 +636,7 @@ struct compiler_unit {
Py_ssize_t u_posonlyargcount; /* number of positional only arguments for block */
Py_ssize_t u_kwonlyargcount; /* number of keyword only arguments for block */
- cfg_builder u_cfg_builder; /* The control flow graph */
+ instr_sequence u_instr_sequence; /* codegen output */
int u_nfblocks;
struct fblockinfo u_fblock[CO_MAXBLOCKS];
@@ -481,7 +672,7 @@ struct compiler {
PyArena *c_arena; /* pointer to memory allocation arena */
};
-#define CFG_BUILDER(C) (&((C)->u->u_cfg_builder))
+#define INSTR_SEQUENCE(C) (&((C)->u->u_instr_sequence))
typedef struct {
@@ -511,9 +702,7 @@ typedef struct {
static int basicblock_next_instr(basicblock *);
-static basicblock *cfg_builder_new_block(cfg_builder *g);
-static int cfg_builder_maybe_start_new_block(cfg_builder *g);
-static int cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, location loc);
+static int codegen_addop_i(instr_sequence *seq, int opcode, Py_ssize_t oparg, location loc);
static void compiler_free(struct compiler *);
static int compiler_error(struct compiler *, location loc, const char *, ...);
@@ -744,7 +933,8 @@ dictbytype(PyObject *src, int scope_type, int flag, Py_ssize_t offset)
return dest;
}
-static void
+#ifndef NDEBUG
+static bool
cfg_builder_check(cfg_builder *g)
{
for (basicblock *block = g->g_block_list; block != NULL; block = block->b_list) {
@@ -759,7 +949,11 @@ cfg_builder_check(cfg_builder *g)
assert (block->b_ialloc == 0);
}
}
+ return true;
}
+#endif
+
+static basicblock *cfg_builder_new_block(cfg_builder *g);
static int
cfg_builder_init(cfg_builder *g)
@@ -777,7 +971,7 @@ cfg_builder_init(cfg_builder *g)
static void
cfg_builder_fini(cfg_builder* g)
{
- cfg_builder_check(g);
+ assert(cfg_builder_check(g));
basicblock *b = g->g_block_list;
while (b != NULL) {
if (b->b_instr) {
@@ -792,7 +986,7 @@ cfg_builder_fini(cfg_builder* g)
static void
compiler_unit_free(struct compiler_unit *u)
{
- cfg_builder_fini(&u->u_cfg_builder);
+ instr_sequence_fini(&u->u_instr_sequence);
Py_CLEAR(u->u_ste);
Py_CLEAR(u->u_name);
Py_CLEAR(u->u_qualname);
@@ -878,13 +1072,6 @@ compiler_set_qualname(struct compiler *c)
return SUCCESS;
}
-static jump_target_label
-cfg_new_label(cfg_builder *g)
-{
- jump_target_label lbl = {g->g_next_free_label++};
- return lbl;
-}
-
/* Allocate a new block and return a pointer to it.
Returns NULL on error.
*/
@@ -912,13 +1099,6 @@ cfg_builder_use_next_block(cfg_builder *g, basicblock *block)
return block;
}
-static int
-cfg_builder_use_label(cfg_builder *g, jump_target_label lbl)
-{
- g->g_current_label = lbl;
- return cfg_builder_maybe_start_new_block(g);
-}
-
static inline int
basicblock_append_instructions(basicblock *target, basicblock *source)
{
@@ -958,40 +1138,15 @@ static int
basicblock_next_instr(basicblock *b)
{
assert(b != NULL);
- if (b->b_instr == NULL) {
- b->b_instr = (struct instr *)PyObject_Calloc(
- DEFAULT_BLOCK_SIZE, sizeof(struct instr));
- if (b->b_instr == NULL) {
- PyErr_NoMemory();
- return ERROR;
- }
- b->b_ialloc = DEFAULT_BLOCK_SIZE;
- }
- else if (b->b_iused == b->b_ialloc) {
- struct instr *tmp;
- size_t oldsize, newsize;
- oldsize = b->b_ialloc * sizeof(struct instr);
- newsize = oldsize << 1;
- if (oldsize > (SIZE_MAX >> 1)) {
- PyErr_NoMemory();
- return ERROR;
- }
+ RETURN_IF_ERROR(
+ ensure_array_large_enough(
+ b->b_iused + 1,
+ (void**)&b->b_instr,
+ &b->b_ialloc,
+ DEFAULT_BLOCK_SIZE,
+ sizeof(struct cfg_instr)));
- if (newsize == 0) {
- PyErr_NoMemory();
- return ERROR;
- }
- b->b_ialloc <<= 1;
- tmp = (struct instr *)PyObject_Realloc(
- (void *)b->b_instr, newsize);
- if (tmp == NULL) {
- PyErr_NoMemory();
- return ERROR;
- }
- b->b_instr = tmp;
- memset((char *)b->b_instr + oldsize, 0, newsize - oldsize);
- }
return b->b_iused++;
}
@@ -1100,7 +1255,7 @@ basicblock_addop(basicblock *b, int opcode, int oparg, location loc)
if (off < 0) {
return ERROR;
}
- struct instr *i = &b->b_instr[off];
+ struct cfg_instr *i = &b->b_instr[off];
i->i_opcode = opcode;
i->i_oparg = oparg;
i->i_target = NULL;
@@ -1115,7 +1270,7 @@ cfg_builder_current_block_is_terminated(cfg_builder *g)
if (IS_LABEL(g->g_current_label)) {
return true;
}
- struct instr *last = basicblock_last_instr(g->g_curblock);
+ struct cfg_instr *last = basicblock_last_instr(g->g_curblock);
return last && IS_TERMINATOR_OPCODE(last->i_opcode);
}
@@ -1135,17 +1290,10 @@ cfg_builder_maybe_start_new_block(cfg_builder *g)
}
static int
-cfg_builder_addop(cfg_builder *g, int opcode, int oparg, location loc)
-{
- RETURN_IF_ERROR(cfg_builder_maybe_start_new_block(g));
- return basicblock_addop(g->g_curblock, opcode, oparg, loc);
-}
-
-static int
-cfg_builder_addop_noarg(cfg_builder *g, int opcode, location loc)
+codegen_addop_noarg(instr_sequence *seq, int opcode, location loc)
{
assert(!HAS_ARG(opcode));
- return cfg_builder_addop(g, opcode, 0, loc);
+ return instr_sequence_addop(seq, opcode, 0, loc);
}
static Py_ssize_t
@@ -1303,7 +1451,7 @@ compiler_addop_load_const(struct compiler *c, location loc, PyObject *o)
if (arg < 0) {
return ERROR;
}
- return cfg_builder_addop_i(CFG_BUILDER(c), LOAD_CONST, arg, loc);
+ return codegen_addop_i(INSTR_SEQUENCE(c), LOAD_CONST, arg, loc);
}
static int
@@ -1314,7 +1462,7 @@ compiler_addop_o(struct compiler *c, location loc,
if (arg < 0) {
return ERROR;
}
- return cfg_builder_addop_i(CFG_BUILDER(c), opcode, arg, loc);
+ return codegen_addop_i(INSTR_SEQUENCE(c), opcode, arg, loc);
}
static int
@@ -1340,12 +1488,12 @@ compiler_addop_name(struct compiler *c, location loc,
arg <<= 1;
arg |= 1;
}
- return cfg_builder_addop_i(CFG_BUILDER(c), opcode, arg, loc);
+ return codegen_addop_i(INSTR_SEQUENCE(c), opcode, arg, loc);
}
/* Add an opcode with an integer argument */
static int
-cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, location loc)
+codegen_addop_i(instr_sequence *seq, int opcode, Py_ssize_t oparg, location loc)
{
/* oparg value is unsigned, but a signed C int is usually used to store
it in the C code (like Python/ceval.c).
@@ -1356,23 +1504,23 @@ cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, location loc)
EXTENDED_ARG is used for 16, 24, and 32-bit arguments. */
int oparg_ = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int);
- return cfg_builder_addop(g, opcode, oparg_, loc);
+ return instr_sequence_addop(seq, opcode, oparg_, loc);
}
static int
-cfg_builder_addop_j(cfg_builder *g, location loc,
+codegen_addop_j(instr_sequence *seq, location loc,
int opcode, jump_target_label target)
{
assert(IS_LABEL(target));
assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode));
- return cfg_builder_addop(g, opcode, target.id, loc);
+ return instr_sequence_addop(seq, opcode, target.id, loc);
}
#define ADDOP(C, LOC, OP) \
- RETURN_IF_ERROR(cfg_builder_addop_noarg(CFG_BUILDER(C), (OP), (LOC)))
+ RETURN_IF_ERROR(codegen_addop_noarg(INSTR_SEQUENCE(C), (OP), (LOC)))
#define ADDOP_IN_SCOPE(C, LOC, OP) { \
- if (cfg_builder_addop_noarg(CFG_BUILDER(C), (OP), (LOC)) < 0) { \
+ if (codegen_addop_noarg(INSTR_SEQUENCE(C), (OP), (LOC)) < 0) { \
compiler_exit_scope(C); \
return ERROR; \
} \
@@ -1407,10 +1555,10 @@ cfg_builder_addop_j(cfg_builder *g, location loc,
RETURN_IF_ERROR(compiler_addop_name((C), (LOC), (OP), (C)->u->u_ ## TYPE, (O)))
#define ADDOP_I(C, LOC, OP, O) \
- RETURN_IF_ERROR(cfg_builder_addop_i(CFG_BUILDER(C), (OP), (O), (LOC)))
+ RETURN_IF_ERROR(codegen_addop_i(INSTR_SEQUENCE(C), (OP), (O), (LOC)))
#define ADDOP_JUMP(C, LOC, OP, O) \
- RETURN_IF_ERROR(cfg_builder_addop_j(CFG_BUILDER(C), (LOC), (OP), (O)))
+ RETURN_IF_ERROR(codegen_addop_j(INSTR_SEQUENCE(C), (LOC), (OP), (O)))
#define ADDOP_COMPARE(C, LOC, CMP) \
RETURN_IF_ERROR(compiler_addcompare((C), (LOC), (cmpop_ty)(CMP)))
@@ -1546,9 +1694,6 @@ compiler_enter_scope(struct compiler *c, identifier name,
c->c_nestlevel++;
- cfg_builder *g = CFG_BUILDER(c);
- RETURN_IF_ERROR(cfg_builder_init(g));
-
if (u->u_scope_type == COMPILER_SCOPE_MODULE) {
loc.lineno = 0;
}
@@ -1582,7 +1727,6 @@ compiler_exit_scope(struct compiler *c)
_PyErr_WriteUnraisableMsg("on removing the last compiler "
"stack item", NULL);
}
- cfg_builder_check(CFG_BUILDER(c));
}
else {
c->u = NULL;
@@ -2321,7 +2465,7 @@ compiler_check_debug_args(struct compiler *c, arguments_ty args)
}
static inline int
-insert_instruction(basicblock *block, int pos, struct instr *instr) {
+insert_instruction(basicblock *block, int pos, struct cfg_instr *instr) {
RETURN_IF_ERROR(basicblock_next_instr(block));
for (int i = block->b_iused - 1; i > pos; i--) {
block->b_instr[i] = block->b_instr[i-1];
@@ -2336,14 +2480,10 @@ wrap_in_stopiteration_handler(struct compiler *c)
NEW_JUMP_TARGET_LABEL(c, handler);
/* Insert SETUP_CLEANUP at start */
- struct instr setup = {
- .i_opcode = SETUP_CLEANUP,
- .i_oparg = handler.id,
- .i_loc = NO_LOCATION,
- .i_target = NULL,
- };
RETURN_IF_ERROR(
- insert_instruction(c->u->u_cfg_builder.g_entryblock, 0, &setup));
+ instr_sequence_insert_instruction(
+ INSTR_SEQUENCE(c), 0,
+ SETUP_CLEANUP, handler.id, NO_LOCATION));
ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None);
ADDOP(c, NO_LOCATION, RETURN_VALUE);
@@ -4032,7 +4172,7 @@ compiler_nameop(struct compiler *c, location loc,
if (op == LOAD_GLOBAL) {
arg <<= 1;
}
- return cfg_builder_addop_i(CFG_BUILDER(c), op, arg, loc);
+ return codegen_addop_i(INSTR_SEQUENCE(c), op, arg, loc);
}
static int
@@ -6051,7 +6191,7 @@ emit_and_reset_fail_pop(struct compiler *c, location loc,
}
while (--pc->fail_pop_size) {
USE_LABEL(c, pc->fail_pop[pc->fail_pop_size]);
- if (cfg_builder_addop_noarg(CFG_BUILDER(c), POP_TOP, loc) < 0) {
+ if (codegen_addop_noarg(INSTR_SEQUENCE(c), POP_TOP, loc) < 0) {
pc->fail_pop_size = 0;
PyObject_Free(pc->fail_pop);
pc->fail_pop = NULL;
@@ -6491,7 +6631,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc)
pc->fail_pop = NULL;
pc->fail_pop_size = 0;
pc->on_top = 0;
- if (cfg_builder_addop_i(CFG_BUILDER(c), COPY, 1, LOC(alt)) < 0 ||
+ if (codegen_addop_i(INSTR_SEQUENCE(c), COPY, 1, LOC(alt)) < 0 ||
compiler_pattern(c, alt, pc) < 0) {
goto error;
}
@@ -6554,7 +6694,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc)
}
}
assert(control);
- if (cfg_builder_addop_j(CFG_BUILDER(c), LOC(alt), JUMP, end) < 0 ||
+ if (codegen_addop_j(INSTR_SEQUENCE(c), LOC(alt), JUMP, end) < 0 ||
emit_and_reset_fail_pop(c, LOC(alt), pc) < 0)
{
goto error;
@@ -6566,7 +6706,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc)
// Need to NULL this for the PyObject_Free call in the error block.
old_pc.fail_pop = NULL;
// No match. Pop the remaining copy of the subject and fail:
- if (cfg_builder_addop_noarg(CFG_BUILDER(c), POP_TOP, LOC(p)) < 0 ||
+ if (codegen_addop_noarg(INSTR_SEQUENCE(c), POP_TOP, LOC(p)) < 0 ||
jump_to_fail_pop(c, LOC(p), pc, JUMP) < 0) {
goto error;
}
@@ -6884,7 +7024,7 @@ stackdepth(basicblock *entryblock, int code_flags)
assert(depth >= 0);
basicblock *next = b->b_next;
for (int i = 0; i < b->b_iused; i++) {
- struct instr *instr = &b->b_instr[i];
+ struct cfg_instr *instr = &b->b_instr[i];
int effect = stack_effect(instr->i_opcode, instr->i_oparg, 0);
if (effect == PY_INVALID_STACK_EFFECT) {
PyErr_Format(PyExc_SystemError,
@@ -6973,7 +7113,7 @@ blocksize(basicblock *b)
}
static basicblock *
-push_except_block(ExceptStack *stack, struct instr *setup) {
+push_except_block(ExceptStack *stack, struct cfg_instr *setup) {
assert(is_block_push(setup));
int opcode = setup->i_opcode;
basicblock * target = setup->i_target;
@@ -7045,7 +7185,7 @@ label_exception_targets(basicblock *entryblock) {
b->b_exceptstack = NULL;
handler = except_stack_top(except_stack);
for (int i = 0; i < b->b_iused; i++) {
- struct instr *instr = &b->b_instr[i];
+ struct cfg_instr *instr = &b->b_instr[i];
if (is_block_push(instr)) {
if (!instr->i_target->b_visited) {
ExceptStack *copy = copy_except_stack(except_stack);
@@ -7123,7 +7263,7 @@ mark_except_handlers(basicblock *entryblock) {
#endif
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
for (int i=0; i < b->b_iused; i++) {
- struct instr *instr = &b->b_instr[i];
+ struct cfg_instr *instr = &b->b_instr[i];
if (is_block_push(instr)) {
instr->i_target->b_except_handler = 1;
}
@@ -7152,7 +7292,7 @@ mark_warm(basicblock *entryblock) {
next->b_visited = 1;
}
for (int i=0; i < b->b_iused; i++) {
- struct instr *instr = &b->b_instr[i];
+ struct cfg_instr *instr = &b->b_instr[i];
if (is_jump(instr) && !instr->i_target->b_visited) {
*sp++ = instr->i_target;
instr->i_target->b_visited = 1;
@@ -7197,7 +7337,7 @@ mark_cold(basicblock *entryblock) {
}
}
for (int i = 0; i < b->b_iused; i++) {
- struct instr *instr = &b->b_instr[i];
+ struct cfg_instr *instr = &b->b_instr[i];
if (is_jump(instr)) {
assert(i == b->b_iused - 1);
basicblock *target = b->b_instr[i].i_target;
@@ -7238,7 +7378,7 @@ push_cold_blocks_to_end(cfg_builder *g, int code_flags) {
b->b_next = explicit_jump;
/* set target */
- struct instr *last = basicblock_last_instr(explicit_jump);
+ struct cfg_instr *last = basicblock_last_instr(explicit_jump);
last->i_target = explicit_jump->b_next;
}
}
@@ -7293,7 +7433,7 @@ static void
convert_exception_handlers_to_nops(basicblock *entryblock) {
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
for (int i = 0; i < b->b_iused; i++) {
- struct instr *instr = &b->b_instr[i];
+ struct cfg_instr *instr = &b->b_instr[i];
if (is_block_push(instr) || instr->i_opcode == POP_BLOCK) {
INSTR_SET_OP0(instr, NOP);
}
@@ -7372,7 +7512,7 @@ assemble_exception_table(struct assembler *a, basicblock *entryblock)
for (b = entryblock; b != NULL; b = b->b_next) {
ioffset = b->b_offset;
for (int i = 0; i < b->b_iused; i++) {
- struct instr *instr = &b->b_instr[i];
+ struct cfg_instr *instr = &b->b_instr[i];
if (instr->i_except != handler) {
if (handler != NULL) {
RETURN_IF_ERROR(
@@ -7542,7 +7682,7 @@ assemble_emit_location(struct assembler* a, location loc, int isize)
*/
static int
-assemble_emit(struct assembler *a, struct instr *i)
+assemble_emit(struct assembler *a, struct cfg_instr *i)
{
Py_ssize_t len = PyBytes_GET_SIZE(a->a_bytecode);
_Py_CODEUNIT *code;
@@ -7562,7 +7702,7 @@ assemble_emit(struct assembler *a, struct instr *i)
static int
normalize_jumps_in_block(cfg_builder *g, basicblock *b) {
- struct instr *last = basicblock_last_instr(b);
+ struct cfg_instr *last = basicblock_last_instr(b);
if (last == NULL || !is_jump(last)) {
return SUCCESS;
}
@@ -7663,7 +7803,7 @@ assemble_jump_offsets(basicblock *entryblock)
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
bsize = b->b_offset;
for (int i = 0; i < b->b_iused; i++) {
- struct instr *instr = &b->b_instr[i];
+ struct cfg_instr *instr = &b->b_instr[i];
int isize = instr_size(instr);
/* Relative jumps are computed relative to
the instruction pointer after fetching
@@ -7735,7 +7875,7 @@ scan_block_for_locals(basicblock *b, basicblock ***sp)
// bit i is set if local i is potentially uninitialized
uint64_t unsafe_mask = b->b_unsafe_locals_mask;
for (int i = 0; i < b->b_iused; i++) {
- struct instr *instr = &b->b_instr[i];
+ struct cfg_instr *instr = &b->b_instr[i];
assert(instr->i_opcode != EXTENDED_ARG);
assert(!IS_SUPERINSTRUCTION_OPCODE(instr->i_opcode));
if (instr->i_except != NULL) {
@@ -7768,7 +7908,7 @@ scan_block_for_locals(basicblock *b, basicblock ***sp)
if (b->b_next && BB_HAS_FALLTHROUGH(b)) {
maybe_push(b->b_next, unsafe_mask, sp);
}
- struct instr *last = basicblock_last_instr(b);
+ struct cfg_instr *last = basicblock_last_instr(b);
if (last && is_jump(last)) {
assert(last->i_target != NULL);
maybe_push(last->i_target, unsafe_mask, sp);
@@ -7791,7 +7931,7 @@ fast_scan_many_locals(basicblock *entryblock, int nlocals)
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
blocknum++;
for (int i = 0; i < b->b_iused; i++) {
- struct instr *instr = &b->b_instr[i];
+ struct cfg_instr *instr = &b->b_instr[i];
assert(instr->i_opcode != EXTENDED_ARG);
assert(!IS_SUPERINSTRUCTION_OPCODE(instr->i_opcode));
int arg = instr->i_oparg;
@@ -8035,7 +8175,6 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist,
PyObject *consts = NULL;
PyObject *localsplusnames = NULL;
PyObject *localspluskinds = NULL;
-
names = dict_keys_inorder(c->u->u_names, 0);
if (!names) {
goto error;
@@ -8121,7 +8260,7 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist,
/* For debugging purposes only */
#if 0
static void
-dump_instr(struct instr *i)
+dump_instr(struct cfg_instr *i)
{
const char *jrel = (is_relative_jump(i)) ? "jrel " : "";
const char *jabs = (is_jump(i) && !is_relative_jump(i))? "jabs " : "";
@@ -8139,6 +8278,12 @@ dump_instr(struct instr *i)
i->i_loc.lineno, i->i_opcode, arg, jabs, jrel);
}
+static inline int
+basicblock_returns(const basicblock *b) {
+ struct cfg_instr *last = basicblock_last_instr(b);
+ return last && (last->i_opcode == RETURN_VALUE || last->i_opcode == RETURN_CONST);
+}
+
static void
dump_basicblock(const basicblock *b)
{
@@ -8211,14 +8356,14 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock,
/* Add the generator prefix instructions. */
if (code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) {
- struct instr make_gen = {
+ struct cfg_instr make_gen = {
.i_opcode = RETURN_GENERATOR,
.i_oparg = 0,
.i_loc = LOCATION(c->u->u_firstlineno, c->u->u_firstlineno, -1, -1),
.i_target = NULL,
};
RETURN_IF_ERROR(insert_instruction(entryblock, 0, &make_gen));
- struct instr pop_top = {
+ struct cfg_instr pop_top = {
.i_opcode = POP_TOP,
.i_oparg = 0,
.i_loc = NO_LOCATION,
@@ -8247,7 +8392,7 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock,
if (oldindex == -1) {
continue;
}
- struct instr make_cell = {
+ struct cfg_instr make_cell = {
.i_opcode = MAKE_CELL,
// This will get fixed in offset_derefs().
.i_oparg = oldindex,
@@ -8261,7 +8406,7 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock,
}
if (nfreevars) {
- struct instr copy_frees = {
+ struct cfg_instr copy_frees = {
.i_opcode = COPY_FREE_VARS,
.i_oparg = nfreevars,
.i_loc = NO_LOCATION,
@@ -8282,7 +8427,7 @@ guarantee_lineno_for_exits(basicblock *entryblock, int firstlineno) {
int lineno = firstlineno;
assert(lineno > 0);
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
- struct instr *last = basicblock_last_instr(b);
+ struct cfg_instr *last = basicblock_last_instr(b);
if (last == NULL) {
continue;
}
@@ -8324,7 +8469,7 @@ fix_cell_offsets(struct compiler *c, basicblock *entryblock, int *fixedmap)
// Then update offsets, either relative to locals or by cell2arg.
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
for (int i = 0; i < b->b_iused; i++) {
- struct instr *inst = &b->b_instr[i];
+ struct cfg_instr *inst = &b->b_instr[i];
// This is called before extended args are generated.
assert(inst->i_opcode != EXTENDED_ARG);
int oldoffset = inst->i_oparg;
@@ -8364,7 +8509,7 @@ no_redundant_nops(cfg_builder *g) {
static bool
no_redundant_jumps(cfg_builder *g) {
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
- struct instr *last = basicblock_last_instr(b);
+ struct cfg_instr *last = basicblock_last_instr(b);
if (last != NULL) {
if (IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) {
assert(last->i_target != b->b_next);
@@ -8382,7 +8527,7 @@ opcode_metadata_is_sane(cfg_builder *g) {
bool result = true;
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
for (int i = 0; i < b->b_iused; i++) {
- struct instr *instr = &b->b_instr[i];
+ struct cfg_instr *instr = &b->b_instr[i];
int opcode = instr->i_opcode;
int oparg = instr->i_oparg;
assert(opcode <= MAX_REAL_OPCODE);
@@ -8426,7 +8571,7 @@ remove_redundant_jumps(cfg_builder *g) {
*/
assert(no_empty_basic_blocks(g));
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
- struct instr *last = basicblock_last_instr(b);
+ struct cfg_instr *last = basicblock_last_instr(b);
assert(last != NULL);
assert(!IS_ASSEMBLER_OPCODE(last->i_opcode));
if (IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) {
@@ -8444,7 +8589,7 @@ remove_redundant_jumps(cfg_builder *g) {
}
static int
-prepare_localsplus(struct compiler* c, int code_flags)
+prepare_localsplus(struct compiler* c, cfg_builder *g, int code_flags)
{
assert(PyDict_GET_SIZE(c->u->u_varnames) < INT_MAX);
assert(PyDict_GET_SIZE(c->u->u_cellvars) < INT_MAX);
@@ -8460,7 +8605,6 @@ prepare_localsplus(struct compiler* c, int code_flags)
return ERROR;
}
- cfg_builder* g = CFG_BUILDER(c);
// This must be called before fix_cell_offsets().
if (insert_prefix_instructions(c, g->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) {
@@ -8474,20 +8618,21 @@ prepare_localsplus(struct compiler* c, int code_flags)
if (numdropped < 0) {
return ERROR;
}
+
nlocalsplus -= numdropped;
return nlocalsplus;
}
static int
-add_return_at_end_of_block(struct compiler *c, int addNone)
+add_return_at_end(struct compiler *c, int addNone)
{
- /* Make sure every block that falls off the end returns None. */
- if (!basicblock_returns(CFG_BUILDER(c)->g_curblock)) {
- if (addNone) {
- ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None);
- }
- ADDOP(c, NO_LOCATION, RETURN_VALUE);
+ /* Make sure every instruction stream that falls off the end returns None.
+ * This also ensures that no jump target offsets are out of bounds.
+ */
+ if (addNone) {
+ ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None);
}
+ ADDOP(c, NO_LOCATION, RETURN_VALUE);
return SUCCESS;
}
@@ -8496,6 +8641,8 @@ assemble(struct compiler *c, int addNone)
{
PyCodeObject *co = NULL;
PyObject *consts = NULL;
+ cfg_builder g_;
+ cfg_builder *g = &g_;
struct assembler a;
memset(&a, 0, sizeof(struct assembler));
@@ -8504,12 +8651,18 @@ assemble(struct compiler *c, int addNone)
return NULL;
}
- if (add_return_at_end_of_block(c, addNone) < 0) {
+ if (add_return_at_end(c, addNone) < 0) {
return NULL;
}
+ /** Preprocessing **/
+ if (instr_sequence_to_cfg(INSTR_SEQUENCE(c), g) < 0) {
+ goto error;
+ }
+ assert(cfg_builder_check(g));
+
int nblocks = 0;
- for (basicblock *b = CFG_BUILDER(c)->g_block_list; b != NULL; b = b->b_list) {
+ for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) {
nblocks++;
}
if ((size_t)nblocks > SIZE_MAX / sizeof(basicblock *)) {
@@ -8517,9 +8670,6 @@ assemble(struct compiler *c, int addNone)
goto error;
}
- cfg_builder *g = CFG_BUILDER(c);
- assert(g->g_entryblock != NULL);
-
/* Set firstlineno if it wasn't explicitly set. */
if (!c->u->u_firstlineno) {
if (g->g_entryblock->b_instr && g->g_entryblock->b_instr->i_loc.lineno) {
@@ -8530,9 +8680,8 @@ assemble(struct compiler *c, int addNone)
}
}
- /** Preprocessing **/
/* Map labels to targets and mark exception handlers */
- if (translate_jump_labels_to_targets(g->g_entryblock)) {
+ if (translate_jump_labels_to_targets(g->g_entryblock) < 0) {
goto error;
}
if (mark_except_handlers(g->g_entryblock) < 0) {
@@ -8550,10 +8699,10 @@ assemble(struct compiler *c, int addNone)
if (optimize_cfg(g, consts, c->c_const_cache)) {
goto error;
}
- if (add_checks_for_loads_of_uninitialized_variables(g->g_entryblock, c) < 0) {
+ if (remove_unused_consts(g->g_entryblock, consts) < 0) {
goto error;
}
- if (remove_unused_consts(g->g_entryblock, consts) < 0) {
+ if (add_checks_for_loads_of_uninitialized_variables(g->g_entryblock, c) < 0) {
goto error;
}
@@ -8570,7 +8719,7 @@ assemble(struct compiler *c, int addNone)
/** Assembly **/
- int nlocalsplus = prepare_localsplus(c, code_flags);
+ int nlocalsplus = prepare_localsplus(c, g, code_flags);
if (nlocalsplus < 0) {
goto error;
}
@@ -8587,7 +8736,6 @@ assemble(struct compiler *c, int addNone)
if (normalize_jumps(g) < 0) {
goto error;
}
-
assert(no_redundant_jumps(g));
assert(opcode_metadata_is_sane(g));
@@ -8655,6 +8803,7 @@ assemble(struct compiler *c, int addNone)
co = makecode(c, &a, consts, maxdepth, nlocalsplus, code_flags);
error:
Py_XDECREF(consts);
+ cfg_builder_fini(g);
assemble_free(&a);
return co;
}
@@ -8684,7 +8833,7 @@ get_const_value(int opcode, int oparg, PyObject *co_consts)
*/
static int
fold_tuple_on_constants(PyObject *const_cache,
- struct instr *inst,
+ struct cfg_instr *inst,
int n, PyObject *consts)
{
/* Pre-conditions */
@@ -8753,7 +8902,7 @@ swaptimize(basicblock *block, int *ix)
// NOTE: "./python -m test test_patma" serves as a good, quick stress test
// for this function. Make sure to blow away cached *.pyc files first!
assert(*ix < block->b_iused);
- struct instr *instructions = &block->b_instr[*ix];
+ struct cfg_instr *instructions = &block->b_instr[*ix];
// Find the length of the current sequence of SWAPs and NOPs, and record the
// maximum depth of the stack manipulations:
assert(instructions[0].i_opcode == SWAP);
@@ -8854,7 +9003,7 @@ static int
next_swappable_instruction(basicblock *block, int i, int lineno)
{
while (++i < block->b_iused) {
- struct instr *instruction = &block->b_instr[i];
+ struct cfg_instr *instruction = &block->b_instr[i];
if (0 <= lineno && instruction->i_loc.lineno != lineno) {
// Optimizing across this instruction could cause user-visible
// changes in the names bound between line tracing events!
@@ -8880,7 +9029,7 @@ apply_static_swaps(basicblock *block, int i)
// SWAPs are to our left, and potential swaperands are to our right:
for (; 0 <= i; i--) {
assert(i < block->b_iused);
- struct instr *swap = &block->b_instr[i];
+ struct cfg_instr *swap = &block->b_instr[i];
if (swap->i_opcode != SWAP) {
if (swap->i_opcode == NOP || SWAPPABLE(swap->i_opcode)) {
// Nope, but we know how to handle these. Keep looking:
@@ -8903,7 +9052,7 @@ apply_static_swaps(basicblock *block, int i)
}
// Success!
INSTR_SET_OP0(swap, NOP);
- struct instr temp = block->b_instr[j];
+ struct cfg_instr temp = block->b_instr[j];
block->b_instr[j] = block->b_instr[k];
block->b_instr[k] = temp;
}
@@ -8913,7 +9062,7 @@ apply_static_swaps(basicblock *block, int i)
// target->i_target using the provided opcode. Return whether or not the
// optimization was successful.
static bool
-jump_thread(struct instr *inst, struct instr *target, int opcode)
+jump_thread(struct cfg_instr *inst, struct cfg_instr *target, int opcode)
{
assert(is_jump(inst));
assert(is_jump(target));
@@ -8938,11 +9087,11 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
{
assert(PyDict_CheckExact(const_cache));
assert(PyList_CheckExact(consts));
- struct instr nop;
+ struct cfg_instr nop;
INSTR_SET_OP0(&nop, NOP);
- struct instr *target;
+ struct cfg_instr *target;
for (int i = 0; i < bb->b_iused; i++) {
- struct instr *inst = &bb->b_instr[i];
+ struct cfg_instr *inst = &bb->b_instr[i];
int oparg = inst->i_oparg;
int nextop = i+1 < bb->b_iused ? bb->b_instr[i+1].i_opcode : 0;
if (HAS_TARGET(inst->i_opcode)) {
@@ -9179,7 +9328,7 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
*/
static int
inline_small_exit_blocks(basicblock *bb) {
- struct instr *last = basicblock_last_instr(bb);
+ struct cfg_instr *last = basicblock_last_instr(bb);
if (last == NULL) {
return 0;
}
@@ -9287,7 +9436,7 @@ mark_reachable(basicblock *entryblock) {
}
for (int i = 0; i < b->b_iused; i++) {
basicblock *target;
- struct instr *instr = &b->b_instr[i];
+ struct cfg_instr *instr = &b->b_instr[i];
if (is_jump(instr) || is_block_push(instr)) {
target = instr->i_target;
if (!target->b_visited) {
@@ -9318,7 +9467,7 @@ eliminate_empty_basic_blocks(cfg_builder *g) {
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
assert(b->b_iused > 0);
for (int i = 0; i < b->b_iused; i++) {
- struct instr *instr = &b->b_instr[i];
+ struct cfg_instr *instr = &b->b_instr[i];
if (HAS_TARGET(instr->i_opcode)) {
basicblock *target = instr->i_target;
while (target->b_iused == 0) {
@@ -9342,7 +9491,7 @@ eliminate_empty_basic_blocks(cfg_builder *g) {
static void
propagate_line_numbers(basicblock *entryblock) {
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
- struct instr *last = basicblock_last_instr(b);
+ struct cfg_instr *last = basicblock_last_instr(b);
if (last == NULL) {
continue;
}
@@ -9398,7 +9547,7 @@ translate_jump_labels_to_targets(basicblock *entryblock)
}
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
for (int i = 0; i < b->b_iused; i++) {
- struct instr *instr = &b->b_instr[i];
+ struct cfg_instr *instr = &b->b_instr[i];
assert(instr->i_target == NULL);
if (HAS_TARGET(instr->i_opcode)) {
int lbl = instr->i_oparg;
@@ -9584,7 +9733,7 @@ duplicate_exits_without_lineno(cfg_builder *g)
*/
basicblock *entryblock = g->g_entryblock;
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
- struct instr *last = basicblock_last_instr(b);
+ struct cfg_instr *last = basicblock_last_instr(b);
assert(last != NULL);
if (is_jump(last)) {
basicblock *target = last->i_target;
@@ -9608,7 +9757,7 @@ duplicate_exits_without_lineno(cfg_builder *g)
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
if (BB_HAS_FALLTHROUGH(b) && b->b_next && b->b_iused > 0) {
if (is_exit_without_lineno(b->b_next)) {
- struct instr *last = basicblock_last_instr(b);
+ struct cfg_instr *last = basicblock_last_instr(b);
assert(last != NULL);
b->b_next->b_instr[0].i_loc = last->i_loc;
}
@@ -9724,7 +9873,7 @@ cfg_to_instructions(cfg_builder *g)
}
for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
for (int i = 0; i < b->b_iused; i++) {
- struct instr *instr = &b->b_instr[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;
@@ -9783,16 +9932,19 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags,
goto finally;
}
- cfg_builder *g = CFG_BUILDER(c);
-
- if (translate_jump_labels_to_targets(g->g_entryblock) < 0) {
+ cfg_builder g;
+ if (instr_sequence_to_cfg(INSTR_SEQUENCE(c), &g) < 0) {
+ goto finally;
+ }
+ if (translate_jump_labels_to_targets(g.g_entryblock) < 0) {
goto finally;
}
- res = cfg_to_instructions(g);
+ res = cfg_to_instructions(&g);
finally:
compiler_exit_scope(c);
+ cfg_builder_fini(&g);
compiler_free(c);
_PyArena_Free(arena);
return res;
@@ -9815,7 +9967,7 @@ _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts)
if (const_cache == NULL) {
goto error;
}
- if (translate_jump_labels_to_targets(g.g_entryblock)) {
+ if (translate_jump_labels_to_targets(g.g_entryblock) < 0) {
goto error;
}
if (optimize_cfg(&g, consts, const_cache) < 0) {
More information about the Python-checkins
mailing list