summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>2022-08-04 13:59:32 (GMT)
committerGitHub <noreply@github.com>2022-08-04 13:59:32 (GMT)
commit000c3874bfa63507293c22249881f6cfc61af311 (patch)
treebc6746e73891ec181462204bf44f1ceeec19a9e8
parent2fef27589e44c91042c2598b5cad6c6ad0516d93 (diff)
downloadcpython-000c3874bfa63507293c22249881f6cfc61af311.zip
cpython-000c3874bfa63507293c22249881f6cfc61af311.tar.gz
cpython-000c3874bfa63507293c22249881f6cfc61af311.tar.bz2
gh-87092: create a 'jump target label' abstraction so that the compiler's codegen stage does not work directly with basic blocks (GH-95398)
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2022-07-28-19-07-06.gh-issue-87092.73IPS1.rst1
-rw-r--r--Python/compile.c739
2 files changed, 386 insertions, 354 deletions
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-07-28-19-07-06.gh-issue-87092.73IPS1.rst b/Misc/NEWS.d/next/Core and Builtins/2022-07-28-19-07-06.gh-issue-87092.73IPS1.rst
new file mode 100644
index 0000000..d4cc4bb
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-07-28-19-07-06.gh-issue-87092.73IPS1.rst
@@ -0,0 +1 @@
+Create a 'jump target label' abstraction in the compiler so that the compiler's codegen stage does not work directly with basic blocks. This prepares the code for changes to the underlying CFG generation mechanism.
diff --git a/Python/compile.c b/Python/compile.c
index 975efa7..3c4dd56 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -139,10 +139,31 @@ struct location {
static struct location NO_LOCATION = {-1, -1, -1, -1};
+typedef struct jump_target_label_ {
+ int id;
+ struct basicblock_ *block;
+} jump_target_label;
+
+static struct jump_target_label_ NO_LABEL = {-1, NULL};
+
+#define SAME_LABEL(L1, L2) ((L1).id == (L2).id)
+#define IS_LABEL(L) (!SAME_LABEL((L), (NO_LABEL)))
+
+#define NEW_JUMP_TARGET_LABEL(C, NAME) \
+ jump_target_label NAME = {cfg_new_label_id(CFG_BUILDER(C)), cfg_builder_new_block(CFG_BUILDER(C))}; \
+ if (!IS_LABEL(NAME)) { \
+ return 0; \
+ }
+
+#define USE_LABEL(C, LBL) cfg_builder_use_label(CFG_BUILDER(C), LBL)
+
struct instr {
int i_opcode;
int i_oparg;
- /* target block (if jump instruction) */
+ /* target block (if jump instruction) -- we temporarily have both the label
+ and the block in the instr. The label is set by front end, and the block
+ is calculated by backend. */
+ jump_target_label i_target_label;
struct basicblock_ *i_target;
/* target block when exception is raised, should not be set by front-end. */
struct basicblock_ *i_except;
@@ -235,6 +256,8 @@ typedef struct basicblock_ {
reverse order that the block are allocated. b_list points to the next
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;
/* 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 */
@@ -309,9 +332,9 @@ enum fblocktype { WHILE_LOOP, FOR_LOOP, TRY_EXCEPT, FINALLY_TRY, FINALLY_END,
struct fblockinfo {
enum fblocktype fb_type;
- basicblock *fb_block;
+ jump_target_label fb_block;
/* (optional) type-specific exit or cleanup block */
- basicblock *fb_exit;
+ jump_target_label fb_exit;
/* (optional) additional information required for unwinding */
void *fb_datum;
};
@@ -334,6 +357,10 @@ typedef struct cfg_builder_ {
basicblock *block_list;
/* pointer to the block currently being constructed */
basicblock *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;
/* The following items change on entry and exit of code blocks.
@@ -418,7 +445,7 @@ typedef struct {
// fail_pop[2]: POP_TOP
// fail_pop[1]: POP_TOP
// fail_pop[0]: NOP
- basicblock **fail_pop;
+ jump_target_label *fail_pop;
// The current length of fail_pop.
Py_ssize_t fail_pop_size;
// The number of items on top of the stack that need to *stay* on top of the
@@ -429,6 +456,7 @@ typedef struct {
static int basicblock_next_instr(basicblock *);
+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, struct location loc);
static void compiler_free(struct compiler *);
@@ -839,6 +867,11 @@ compiler_set_qualname(struct compiler *c)
return 1;
}
+static int
+cfg_new_label_id(cfg_builder *g)
+{
+ return g->g_next_free_label++;
+}
/* Allocate a new block and return a pointer to it.
Returns NULL on error.
@@ -854,6 +887,7 @@ cfg_builder_new_block(cfg_builder *g)
/* Extend the singly linked list of blocks with new block. */
b->b_list = g->block_list;
g->block_list = b;
+ b->b_label = -1;
return b;
}
@@ -866,16 +900,11 @@ cfg_builder_use_next_block(cfg_builder *g, basicblock *block)
return block;
}
-static basicblock *
-compiler_new_block(struct compiler *c)
-{
- return cfg_builder_new_block(CFG_BUILDER(c));
-}
-
-static basicblock *
-compiler_use_next_block(struct compiler *c, basicblock *block)
+static int
+cfg_builder_use_label(cfg_builder *g, jump_target_label lbl)
{
- return cfg_builder_use_next_block(CFG_BUILDER(c), block);
+ g->g_current_label = lbl;
+ return cfg_builder_maybe_start_new_block(g);
}
static basicblock *
@@ -1254,16 +1283,16 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
static int
basicblock_addop(basicblock *b, int opcode, int oparg,
- basicblock *target, struct location loc)
+ jump_target_label target, struct location loc)
{
assert(IS_WITHIN_OPCODE_RANGE(opcode));
assert(!IS_ASSEMBLER_OPCODE(opcode));
assert(HAS_ARG(opcode) || oparg == 0);
assert(0 <= oparg && oparg < (1 << 30));
- assert((target == NULL) ||
+ assert(!IS_LABEL(target) ||
IS_JUMP_OPCODE(opcode) ||
IS_BLOCK_PUSH_OPCODE(opcode));
- assert(oparg == 0 || target == NULL);
+ assert(oparg == 0 || !IS_LABEL(target));
int off = basicblock_next_instr(b);
if (off < 0) {
@@ -1272,24 +1301,51 @@ basicblock_addop(basicblock *b, int opcode, int oparg,
struct instr *i = &b->b_instr[off];
i->i_opcode = opcode;
i->i_oparg = oparg;
- i->i_target = target;
+ i->i_target_label = target;
+ i->i_target = NULL;
i->i_loc = loc;
return 1;
}
-static int
-cfg_builder_addop(cfg_builder *g, int opcode, int oparg, basicblock *target,
- struct location loc)
+static bool
+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->curblock);
- if (last && IS_TERMINATOR_OPCODE(last->i_opcode)) {
- basicblock *b = cfg_builder_new_block(g);
+ return last && IS_TERMINATOR_OPCODE(last->i_opcode);
+}
+
+static int
+cfg_builder_maybe_start_new_block(cfg_builder *g)
+{
+ if (cfg_builder_current_block_is_terminated(g)) {
+ basicblock *b;
+ if (IS_LABEL(g->g_current_label)) {
+ b = g->g_current_label.block;
+ b->b_label = g->g_current_label.id;
+ g->g_current_label = NO_LABEL;
+ }
+ else {
+ b = cfg_builder_new_block(g);
+ }
if (b == NULL) {
return -1;
}
cfg_builder_use_next_block(g, b);
}
+ return 0;
+}
+
+static int
+cfg_builder_addop(cfg_builder *g, int opcode, int oparg, jump_target_label target,
+ struct location loc)
+{
+ if (cfg_builder_maybe_start_new_block(g) != 0) {
+ return -1;
+ }
return basicblock_addop(g->curblock, opcode, oparg, target, loc);
}
@@ -1297,7 +1353,7 @@ static int
cfg_builder_addop_noarg(cfg_builder *g, int opcode, struct location loc)
{
assert(!HAS_ARG(opcode));
- return cfg_builder_addop(g, opcode, 0, NULL, loc);
+ return cfg_builder_addop(g, opcode, 0, NO_LABEL, loc);
}
static Py_ssize_t
@@ -1509,13 +1565,13 @@ cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, struct locatio
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_, NULL, loc);
+ return cfg_builder_addop(g, opcode, oparg_, NO_LABEL, loc);
}
static int
-cfg_builder_addop_j(cfg_builder *g, int opcode, basicblock *target, struct location loc)
+cfg_builder_addop_j(cfg_builder *g, int opcode, jump_target_label target, struct location loc)
{
- assert(target != NULL);
+ assert(IS_LABEL(target));
assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode));
return cfg_builder_addop(g, opcode, 0, target, loc);
}
@@ -1744,6 +1800,7 @@ compiler_enter_scope(struct compiler *c, identifier name,
if (block == NULL)
return 0;
g->curblock = g->cfg_entryblock = block;
+ g->g_current_label = NO_LABEL;
if (u->u_scope_type == COMPILER_SCOPE_MODULE) {
c->u->u_loc.lineno = 0;
@@ -1863,8 +1920,8 @@ find_ann(asdl_stmt_seq *stmts)
*/
static int
-compiler_push_fblock(struct compiler *c, enum fblocktype t, basicblock *b,
- basicblock *exit, void *datum)
+compiler_push_fblock(struct compiler *c, enum fblocktype t, jump_target_label block_label,
+ jump_target_label exit, void *datum)
{
struct fblockinfo *f;
if (c->u->u_nfblocks >= CO_MAXBLOCKS) {
@@ -1872,20 +1929,20 @@ compiler_push_fblock(struct compiler *c, enum fblocktype t, basicblock *b,
}
f = &c->u->u_fblock[c->u->u_nfblocks++];
f->fb_type = t;
- f->fb_block = b;
+ f->fb_block = block_label;
f->fb_exit = exit;
f->fb_datum = datum;
return 1;
}
static void
-compiler_pop_fblock(struct compiler *c, enum fblocktype t, basicblock *b)
+compiler_pop_fblock(struct compiler *c, enum fblocktype t, jump_target_label block_label)
{
struct compiler_unit *u = c->u;
assert(u->u_nfblocks > 0);
u->u_nfblocks--;
assert(u->u_fblock[u->u_nfblocks].fb_type == t);
- assert(u->u_fblock[u->u_nfblocks].fb_block == b);
+ assert(SAME_LABEL(u->u_fblock[u->u_nfblocks].fb_block, block_label));
}
static int
@@ -1900,20 +1957,19 @@ compiler_call_exit_with_nones(struct compiler *c) {
static int
compiler_add_yield_from(struct compiler *c, int await)
{
- basicblock *start, *resume, *exit;
- start = compiler_new_block(c);
- resume = compiler_new_block(c);
- exit = compiler_new_block(c);
- if (start == NULL || resume == NULL || exit == NULL) {
- return 0;
- }
- compiler_use_next_block(c, start);
+ NEW_JUMP_TARGET_LABEL(c, start);
+ NEW_JUMP_TARGET_LABEL(c, resume);
+ NEW_JUMP_TARGET_LABEL(c, exit);
+
+ USE_LABEL(c, start);
ADDOP_JUMP(c, SEND, exit);
- compiler_use_next_block(c, resume);
+
+ USE_LABEL(c, resume);
ADDOP_I(c, YIELD_VALUE, 0);
ADDOP_I(c, RESUME, await ? 3 : 2);
ADDOP_JUMP(c, JUMP_NO_INTERRUPT, start);
- compiler_use_next_block(c, exit);
+
+ USE_LABEL(c, exit);
return 1;
}
@@ -1965,14 +2021,14 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
/* This POP_BLOCK gets the line number of the unwinding statement */
ADDOP(c, POP_BLOCK);
if (preserve_tos) {
- if (!compiler_push_fblock(c, POP_VALUE, NULL, NULL, NULL)) {
+ if (!compiler_push_fblock(c, POP_VALUE, NO_LABEL, NO_LABEL, NULL)) {
return 0;
}
}
/* Emit the finally block */
VISIT_SEQ(c, stmt, info->fb_datum);
if (preserve_tos) {
- compiler_pop_fblock(c, POP_VALUE, NULL);
+ compiler_pop_fblock(c, POP_VALUE, NO_LABEL);
}
/* The finally block should appear to execute after the
* statement causing the unwinding, so make the unwinding
@@ -2816,7 +2872,7 @@ static int compiler_addcompare(struct compiler *c, cmpop_ty op)
static int
-compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond)
+compiler_jump_if(struct compiler *c, expr_ty e, jump_target_label next, int cond)
{
switch (e->kind) {
case UnaryOp_kind:
@@ -2829,11 +2885,10 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond)
Py_ssize_t i, n = asdl_seq_LEN(s) - 1;
assert(n >= 0);
int cond2 = e->v.BoolOp.op == Or;
- basicblock *next2 = next;
+ jump_target_label next2 = next;
if (!cond2 != !cond) {
- next2 = compiler_new_block(c);
- if (next2 == NULL)
- return 0;
+ NEW_JUMP_TARGET_LABEL(c, new_next2);
+ next2 = new_next2;
}
for (i = 0; i < n; ++i) {
if (!compiler_jump_if(c, (expr_ty)asdl_seq_GET(s, i), next2, cond2))
@@ -2841,27 +2896,25 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond)
}
if (!compiler_jump_if(c, (expr_ty)asdl_seq_GET(s, n), next, cond))
return 0;
- if (next2 != next)
- compiler_use_next_block(c, next2);
+ if (!SAME_LABEL(next2, next)) {
+ USE_LABEL(c, next2);
+ }
return 1;
}
case IfExp_kind: {
- basicblock *end, *next2;
- end = compiler_new_block(c);
- if (end == NULL)
- return 0;
- next2 = compiler_new_block(c);
- if (next2 == NULL)
- return 0;
+ NEW_JUMP_TARGET_LABEL(c, end);
+ NEW_JUMP_TARGET_LABEL(c, next2);
if (!compiler_jump_if(c, e->v.IfExp.test, next2, 0))
return 0;
if (!compiler_jump_if(c, e->v.IfExp.body, next, cond))
return 0;
ADDOP_JUMP_NOLINE(c, JUMP, end);
- compiler_use_next_block(c, next2);
+
+ USE_LABEL(c, next2);
if (!compiler_jump_if(c, e->v.IfExp.orelse, next, cond))
return 0;
- compiler_use_next_block(c, end);
+
+ USE_LABEL(c, end);
return 1;
}
case Compare_kind: {
@@ -2870,9 +2923,7 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond)
if (!check_compare(c, e)) {
return 0;
}
- basicblock *cleanup = compiler_new_block(c);
- if (cleanup == NULL)
- return 0;
+ NEW_JUMP_TARGET_LABEL(c, cleanup);
VISIT(c, expr, e->v.Compare.left);
for (i = 0; i < n; i++) {
VISIT(c, expr,
@@ -2885,16 +2936,16 @@ 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));
ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, n));
ADDOP_JUMP(c, cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next);
- basicblock *end = compiler_new_block(c);
- if (end == NULL)
- return 0;
+ NEW_JUMP_TARGET_LABEL(c, end);
ADDOP_JUMP_NOLINE(c, JUMP, end);
- compiler_use_next_block(c, cleanup);
+
+ USE_LABEL(c, cleanup);
ADDOP(c, POP_TOP);
if (!cond) {
ADDOP_JUMP_NOLINE(c, JUMP, next);
}
- compiler_use_next_block(c, end);
+
+ USE_LABEL(c, end);
return 1;
}
/* fallback to general implementation */
@@ -2914,22 +2965,19 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond)
static int
compiler_ifexp(struct compiler *c, expr_ty e)
{
- basicblock *end, *next;
-
assert(e->kind == IfExp_kind);
- end = compiler_new_block(c);
- if (end == NULL)
- return 0;
- next = compiler_new_block(c);
- if (next == NULL)
- return 0;
+ NEW_JUMP_TARGET_LABEL(c, end);
+ NEW_JUMP_TARGET_LABEL(c, next);
+
if (!compiler_jump_if(c, e->v.IfExp.test, next, 0))
return 0;
VISIT(c, expr, e->v.IfExp.body);
ADDOP_JUMP_NOLINE(c, JUMP, end);
- compiler_use_next_block(c, next);
+
+ USE_LABEL(c, next);
VISIT(c, expr, e->v.IfExp.orelse);
- compiler_use_next_block(c, end);
+
+ USE_LABEL(c, end);
return 1;
}
@@ -2993,17 +3041,12 @@ compiler_lambda(struct compiler *c, expr_ty e)
static int
compiler_if(struct compiler *c, stmt_ty s)
{
- basicblock *end, *next;
+ jump_target_label next;
assert(s->kind == If_kind);
- end = compiler_new_block(c);
- if (end == NULL) {
- return 0;
- }
+ NEW_JUMP_TARGET_LABEL(c, end);
if (asdl_seq_LEN(s->v.If.orelse)) {
- next = compiler_new_block(c);
- if (next == NULL) {
- return 0;
- }
+ NEW_JUMP_TARGET_LABEL(c, orelse);
+ next = orelse;
}
else {
next = end;
@@ -3014,44 +3057,46 @@ compiler_if(struct compiler *c, stmt_ty s)
VISIT_SEQ(c, stmt, s->v.If.body);
if (asdl_seq_LEN(s->v.If.orelse)) {
ADDOP_JUMP_NOLINE(c, JUMP, end);
- compiler_use_next_block(c, next);
+
+ USE_LABEL(c, next);
VISIT_SEQ(c, stmt, s->v.If.orelse);
}
- compiler_use_next_block(c, end);
+
+ USE_LABEL(c, end);
return 1;
}
static int
compiler_for(struct compiler *c, stmt_ty s)
{
- basicblock *start, *body, *cleanup, *end;
+ NEW_JUMP_TARGET_LABEL(c, start);
+ NEW_JUMP_TARGET_LABEL(c, body);
+ NEW_JUMP_TARGET_LABEL(c, cleanup);
+ NEW_JUMP_TARGET_LABEL(c, end);
- start = compiler_new_block(c);
- body = compiler_new_block(c);
- cleanup = compiler_new_block(c);
- end = compiler_new_block(c);
- if (start == NULL || body == NULL || end == NULL || cleanup == NULL) {
- return 0;
- }
if (!compiler_push_fblock(c, FOR_LOOP, start, end, NULL)) {
return 0;
}
VISIT(c, expr, s->v.For.iter);
ADDOP(c, GET_ITER);
- compiler_use_next_block(c, start);
+
+ USE_LABEL(c, start);
ADDOP_JUMP(c, FOR_ITER, cleanup);
- compiler_use_next_block(c, body);
+
+ USE_LABEL(c, body);
VISIT(c, expr, s->v.For.target);
VISIT_SEQ(c, stmt, s->v.For.body);
/* Mark jump as artificial */
UNSET_LOC(c);
ADDOP_JUMP(c, JUMP, start);
- compiler_use_next_block(c, cleanup);
+
+ USE_LABEL(c, cleanup);
compiler_pop_fblock(c, FOR_LOOP, start);
VISIT_SEQ(c, stmt, s->v.For.orelse);
- compiler_use_next_block(c, end);
+
+ USE_LABEL(c, end);
return 1;
}
@@ -3059,24 +3104,20 @@ compiler_for(struct compiler *c, stmt_ty s)
static int
compiler_async_for(struct compiler *c, stmt_ty s)
{
- basicblock *start, *except, *end;
if (IS_TOP_LEVEL_AWAIT(c)){
c->u->u_ste->ste_coroutine = 1;
} else if (c->u->u_scope_type != COMPILER_SCOPE_ASYNC_FUNCTION) {
return compiler_error(c, "'async for' outside async function");
}
- start = compiler_new_block(c);
- except = compiler_new_block(c);
- end = compiler_new_block(c);
+ NEW_JUMP_TARGET_LABEL(c, start);
+ NEW_JUMP_TARGET_LABEL(c, except);
+ NEW_JUMP_TARGET_LABEL(c, end);
- if (start == NULL || except == NULL || end == NULL) {
- return 0;
- }
VISIT(c, expr, s->v.AsyncFor.iter);
ADDOP(c, GET_AITER);
- compiler_use_next_block(c, start);
+ USE_LABEL(c, start);
if (!compiler_push_fblock(c, FOR_LOOP, start, end, NULL)) {
return 0;
}
@@ -3097,7 +3138,7 @@ compiler_async_for(struct compiler *c, stmt_ty s)
compiler_pop_fblock(c, FOR_LOOP, start);
/* Except block for __anext__ */
- compiler_use_next_block(c, except);
+ USE_LABEL(c, except);
/* Use same line number as the iterator,
* as the END_ASYNC_FOR succeeds the `for`, not the body. */
@@ -3107,23 +3148,19 @@ compiler_async_for(struct compiler *c, stmt_ty s)
/* `else` block */
VISIT_SEQ(c, stmt, s->v.For.orelse);
- compiler_use_next_block(c, end);
-
+ USE_LABEL(c, end);
return 1;
}
static int
compiler_while(struct compiler *c, stmt_ty s)
{
- basicblock *loop, *body, *end, *anchor = NULL;
- loop = compiler_new_block(c);
- body = compiler_new_block(c);
- anchor = compiler_new_block(c);
- end = compiler_new_block(c);
- if (loop == NULL || body == NULL || anchor == NULL || end == NULL) {
- return 0;
- }
- compiler_use_next_block(c, loop);
+ NEW_JUMP_TARGET_LABEL(c, loop);
+ NEW_JUMP_TARGET_LABEL(c, body);
+ NEW_JUMP_TARGET_LABEL(c, end);
+ NEW_JUMP_TARGET_LABEL(c, anchor);
+
+ USE_LABEL(c, loop);
if (!compiler_push_fblock(c, WHILE_LOOP, loop, end, NULL)) {
return 0;
}
@@ -3131,7 +3168,7 @@ compiler_while(struct compiler *c, stmt_ty s)
return 0;
}
- compiler_use_next_block(c, body);
+ USE_LABEL(c, body);
VISIT_SEQ(c, stmt, s->v.While.body);
SET_LOC(c, s);
if (!compiler_jump_if(c, s->v.While.test, body, 1)) {
@@ -3140,12 +3177,12 @@ compiler_while(struct compiler *c, stmt_ty s)
compiler_pop_fblock(c, WHILE_LOOP, loop);
- compiler_use_next_block(c, anchor);
+ USE_LABEL(c, anchor);
if (s->v.While.orelse) {
VISIT_SEQ(c, stmt, s->v.While.orelse);
}
- compiler_use_next_block(c, end);
+ USE_LABEL(c, end);
return 1;
}
@@ -3257,18 +3294,15 @@ compiler_continue(struct compiler *c)
static int
compiler_try_finally(struct compiler *c, stmt_ty s)
{
- basicblock *body, *end, *exit, *cleanup;
+ NEW_JUMP_TARGET_LABEL(c, body);
+ NEW_JUMP_TARGET_LABEL(c, end);
+ NEW_JUMP_TARGET_LABEL(c, exit);
+ NEW_JUMP_TARGET_LABEL(c, cleanup);
- body = compiler_new_block(c);
- end = compiler_new_block(c);
- exit = compiler_new_block(c);
- cleanup = compiler_new_block(c);
- if (body == NULL || end == NULL || exit == NULL || cleanup == NULL) {
- return 0;
- }
/* `try` block */
ADDOP_JUMP(c, SETUP_FINALLY, end);
- compiler_use_next_block(c, body);
+
+ USE_LABEL(c, body);
if (!compiler_push_fblock(c, FINALLY_TRY, body, end, s->v.Try.finalbody))
return 0;
if (s->v.Try.handlers && asdl_seq_LEN(s->v.Try.handlers)) {
@@ -3283,44 +3317,36 @@ compiler_try_finally(struct compiler *c, stmt_ty s)
VISIT_SEQ(c, stmt, s->v.Try.finalbody);
ADDOP_JUMP_NOLINE(c, JUMP, exit);
/* `finally` block */
- compiler_use_next_block(c, end);
+
+ USE_LABEL(c, end);
UNSET_LOC(c);
ADDOP_JUMP(c, SETUP_CLEANUP, cleanup);
ADDOP(c, PUSH_EXC_INFO);
- if (!compiler_push_fblock(c, FINALLY_END, end, NULL, NULL))
+ if (!compiler_push_fblock(c, FINALLY_END, end, NO_LABEL, NULL))
return 0;
VISIT_SEQ(c, stmt, s->v.Try.finalbody);
compiler_pop_fblock(c, FINALLY_END, end);
ADDOP_I(c, RERAISE, 0);
- compiler_use_next_block(c, cleanup);
+
+ USE_LABEL(c, cleanup);
POP_EXCEPT_AND_RERAISE(c);
- compiler_use_next_block(c, exit);
+
+ USE_LABEL(c, exit);
return 1;
}
static int
compiler_try_star_finally(struct compiler *c, stmt_ty s)
{
- basicblock *body = compiler_new_block(c);
- if (body == NULL) {
- return 0;
- }
- basicblock *end = compiler_new_block(c);
- if (!end) {
- return 0;
- }
- basicblock *exit = compiler_new_block(c);
- if (!exit) {
- return 0;
- }
- basicblock *cleanup = compiler_new_block(c);
- if (!cleanup) {
- return 0;
- }
+ NEW_JUMP_TARGET_LABEL(c, body);
+ NEW_JUMP_TARGET_LABEL(c, end);
+ NEW_JUMP_TARGET_LABEL(c, exit);
+ NEW_JUMP_TARGET_LABEL(c, cleanup);
/* `try` block */
ADDOP_JUMP(c, SETUP_FINALLY, end);
- compiler_use_next_block(c, body);
+
+ USE_LABEL(c, body);
if (!compiler_push_fblock(c, FINALLY_TRY, body, end, s->v.TryStar.finalbody)) {
return 0;
}
@@ -3336,21 +3362,24 @@ compiler_try_star_finally(struct compiler *c, stmt_ty s)
compiler_pop_fblock(c, FINALLY_TRY, body);
VISIT_SEQ(c, stmt, s->v.TryStar.finalbody);
ADDOP_JUMP_NOLINE(c, JUMP, exit);
+
/* `finally` block */
- compiler_use_next_block(c, end);
+ USE_LABEL(c, end);
UNSET_LOC(c);
ADDOP_JUMP(c, SETUP_CLEANUP, cleanup);
ADDOP(c, PUSH_EXC_INFO);
- if (!compiler_push_fblock(c, FINALLY_END, end, NULL, NULL)) {
+ if (!compiler_push_fblock(c, FINALLY_END, end, NO_LABEL, NULL)) {
return 0;
}
VISIT_SEQ(c, stmt, s->v.TryStar.finalbody);
compiler_pop_fblock(c, FINALLY_END, end);
ADDOP_I(c, RERAISE, 0);
- compiler_use_next_block(c, cleanup);
+
+ USE_LABEL(c, cleanup);
POP_EXCEPT_AND_RERAISE(c);
- compiler_use_next_block(c, exit);
+
+ USE_LABEL(c, exit);
return 1;
}
@@ -3386,18 +3415,17 @@ compiler_try_star_finally(struct compiler *c, stmt_ty s)
static int
compiler_try_except(struct compiler *c, stmt_ty s)
{
- basicblock *body, *except, *end, *cleanup;
Py_ssize_t i, n;
- body = compiler_new_block(c);
- except = compiler_new_block(c);
- end = compiler_new_block(c);
- cleanup = compiler_new_block(c);
- if (body == NULL || except == NULL || end == NULL || cleanup == NULL)
- return 0;
+ NEW_JUMP_TARGET_LABEL(c, body);
+ NEW_JUMP_TARGET_LABEL(c, except);
+ NEW_JUMP_TARGET_LABEL(c, end);
+ NEW_JUMP_TARGET_LABEL(c, cleanup);
+
ADDOP_JUMP(c, SETUP_FINALLY, except);
- compiler_use_next_block(c, body);
- if (!compiler_push_fblock(c, TRY_EXCEPT, body, NULL, NULL))
+
+ USE_LABEL(c, body);
+ if (!compiler_push_fblock(c, TRY_EXCEPT, body, NO_LABEL, NULL))
return 0;
VISIT_SEQ(c, stmt, s->v.Try.body);
compiler_pop_fblock(c, TRY_EXCEPT, body);
@@ -3407,13 +3435,14 @@ compiler_try_except(struct compiler *c, stmt_ty s)
}
ADDOP_JUMP_NOLINE(c, JUMP, end);
n = asdl_seq_LEN(s->v.Try.handlers);
- compiler_use_next_block(c, except);
+
+ USE_LABEL(c, except);
UNSET_LOC(c);
ADDOP_JUMP(c, SETUP_CLEANUP, cleanup);
ADDOP(c, PUSH_EXC_INFO);
/* Runtime will push a block here, so we need to account for that */
- if (!compiler_push_fblock(c, EXCEPTION_HANDLER, NULL, NULL, NULL))
+ if (!compiler_push_fblock(c, EXCEPTION_HANDLER, NO_LABEL, NO_LABEL, NULL))
return 0;
for (i = 0; i < n; i++) {
excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET(
@@ -3422,22 +3451,16 @@ compiler_try_except(struct compiler *c, stmt_ty s)
if (!handler->v.ExceptHandler.type && i < n-1) {
return compiler_error(c, "default 'except:' must be last");
}
- except = compiler_new_block(c);
- if (except == NULL)
- return 0;
+ NEW_JUMP_TARGET_LABEL(c, next_except);
+ except = next_except;
if (handler->v.ExceptHandler.type) {
VISIT(c, expr, handler->v.ExceptHandler.type);
ADDOP(c, CHECK_EXC_MATCH);
ADDOP_JUMP(c, POP_JUMP_IF_FALSE, except);
}
if (handler->v.ExceptHandler.name) {
- basicblock *cleanup_end, *cleanup_body;
-
- cleanup_end = compiler_new_block(c);
- cleanup_body = compiler_new_block(c);
- if (cleanup_end == NULL || cleanup_body == NULL) {
- return 0;
- }
+ NEW_JUMP_TARGET_LABEL(c, cleanup_end);
+ NEW_JUMP_TARGET_LABEL(c, cleanup_body);
compiler_nameop(c, handler->v.ExceptHandler.name, Store);
@@ -3454,8 +3477,9 @@ compiler_try_except(struct compiler *c, stmt_ty s)
/* second try: */
ADDOP_JUMP(c, SETUP_CLEANUP, cleanup_end);
- compiler_use_next_block(c, cleanup_body);
- if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NULL, handler->v.ExceptHandler.name))
+
+ USE_LABEL(c, cleanup_body);
+ if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NO_LABEL, handler->v.ExceptHandler.name))
return 0;
/* second # body */
@@ -3472,7 +3496,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
ADDOP_JUMP(c, JUMP, end);
/* except: */
- compiler_use_next_block(c, cleanup_end);
+ USE_LABEL(c, cleanup_end);
/* name = None; del name; # Mark as artificial */
UNSET_LOC(c);
@@ -3484,15 +3508,12 @@ compiler_try_except(struct compiler *c, stmt_ty s)
ADDOP_I(c, RERAISE, 1);
}
else {
- basicblock *cleanup_body;
-
- cleanup_body = compiler_new_block(c);
- if (!cleanup_body)
- return 0;
+ NEW_JUMP_TARGET_LABEL(c, cleanup_body);
ADDOP(c, POP_TOP); /* exc_value */
- compiler_use_next_block(c, cleanup_body);
- if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NULL, NULL))
+
+ USE_LABEL(c, cleanup_body);
+ if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NO_LABEL, NULL))
return 0;
VISIT_SEQ(c, stmt, handler->v.ExceptHandler.body);
compiler_pop_fblock(c, HANDLER_CLEANUP, cleanup_body);
@@ -3501,15 +3522,18 @@ compiler_try_except(struct compiler *c, stmt_ty s)
ADDOP(c, POP_EXCEPT);
ADDOP_JUMP(c, JUMP, end);
}
- compiler_use_next_block(c, except);
+
+ USE_LABEL(c, except);
}
/* Mark as artificial */
UNSET_LOC(c);
- compiler_pop_fblock(c, EXCEPTION_HANDLER, NULL);
+ compiler_pop_fblock(c, EXCEPTION_HANDLER, NO_LABEL);
ADDOP_I(c, RERAISE, 0);
- compiler_use_next_block(c, cleanup);
+
+ USE_LABEL(c, cleanup);
POP_EXCEPT_AND_RERAISE(c);
- compiler_use_next_block(c, end);
+
+ USE_LABEL(c, end);
return 1;
}
@@ -3565,34 +3589,17 @@ compiler_try_except(struct compiler *c, stmt_ty s)
static int
compiler_try_star_except(struct compiler *c, stmt_ty s)
{
- basicblock *body = compiler_new_block(c);
- if (body == NULL) {
- return 0;
- }
- basicblock *except = compiler_new_block(c);
- if (except == NULL) {
- return 0;
- }
- basicblock *orelse = compiler_new_block(c);
- if (orelse == NULL) {
- return 0;
- }
- basicblock *end = compiler_new_block(c);
- if (end == NULL) {
- return 0;
- }
- basicblock *cleanup = compiler_new_block(c);
- if (cleanup == NULL) {
- return 0;
- }
- basicblock *reraise_star = compiler_new_block(c);
- if (reraise_star == NULL) {
- return 0;
- }
+ NEW_JUMP_TARGET_LABEL(c, body);
+ NEW_JUMP_TARGET_LABEL(c, except);
+ NEW_JUMP_TARGET_LABEL(c, orelse);
+ NEW_JUMP_TARGET_LABEL(c, end);
+ NEW_JUMP_TARGET_LABEL(c, cleanup);
+ NEW_JUMP_TARGET_LABEL(c, reraise_star);
ADDOP_JUMP(c, SETUP_FINALLY, except);
- compiler_use_next_block(c, body);
- if (!compiler_push_fblock(c, TRY_EXCEPT, body, NULL, NULL)) {
+
+ USE_LABEL(c, body);
+ if (!compiler_push_fblock(c, TRY_EXCEPT, body, NO_LABEL, NULL)) {
return 0;
}
VISIT_SEQ(c, stmt, s->v.TryStar.body);
@@ -3600,28 +3607,24 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
ADDOP_NOLINE(c, POP_BLOCK);
ADDOP_JUMP_NOLINE(c, JUMP, orelse);
Py_ssize_t n = asdl_seq_LEN(s->v.TryStar.handlers);
- compiler_use_next_block(c, except);
+
+ USE_LABEL(c, except);
UNSET_LOC(c);
ADDOP_JUMP(c, SETUP_CLEANUP, cleanup);
ADDOP(c, PUSH_EXC_INFO);
/* Runtime will push a block here, so we need to account for that */
if (!compiler_push_fblock(c, EXCEPTION_GROUP_HANDLER,
- NULL, NULL, "except handler")) {
+ NO_LABEL, NO_LABEL, "except handler")) {
return 0;
}
for (Py_ssize_t i = 0; i < n; i++) {
excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET(
s->v.TryStar.handlers, i);
SET_LOC(c, handler);
- except = compiler_new_block(c);
- if (except == NULL) {
- return 0;
- }
- basicblock *handle_match = compiler_new_block(c);
- if (handle_match == NULL) {
- return 0;
- }
+ NEW_JUMP_TARGET_LABEL(c, next_except);
+ except = next_except;
+ NEW_JUMP_TARGET_LABEL(c, handle_match);
if (i == 0) {
/* Push the original EG into the stack */
/*
@@ -3648,16 +3651,10 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
ADDOP_JUMP(c, JUMP, except);
}
- compiler_use_next_block(c, handle_match);
+ USE_LABEL(c, handle_match);
- basicblock *cleanup_end = compiler_new_block(c);
- if (cleanup_end == NULL) {
- return 0;
- }
- basicblock *cleanup_body = compiler_new_block(c);
- if (cleanup_body == NULL) {
- return 0;
- }
+ NEW_JUMP_TARGET_LABEL(c, cleanup_end);
+ NEW_JUMP_TARGET_LABEL(c, cleanup_body);
if (handler->v.ExceptHandler.name) {
compiler_nameop(c, handler->v.ExceptHandler.name, Store);
@@ -3678,8 +3675,9 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
*/
/* second try: */
ADDOP_JUMP(c, SETUP_CLEANUP, cleanup_end);
- compiler_use_next_block(c, cleanup_body);
- if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NULL, handler->v.ExceptHandler.name))
+
+ USE_LABEL(c, cleanup_body);
+ if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NO_LABEL, handler->v.ExceptHandler.name))
return 0;
/* second # body */
@@ -3696,7 +3694,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
ADDOP_JUMP(c, JUMP, except);
/* except: */
- compiler_use_next_block(c, cleanup_end);
+ USE_LABEL(c, cleanup_end);
/* name = None; del name; # Mark as artificial */
UNSET_LOC(c);
@@ -3710,9 +3708,9 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
/* add exception raised to the res list */
ADDOP_I(c, LIST_APPEND, 3); // exc
ADDOP(c, POP_TOP); // lasti
-
ADDOP_JUMP(c, JUMP, except);
- compiler_use_next_block(c, except);
+
+ USE_LABEL(c, except);
if (i == n - 1) {
/* Add exc to the list (if not None it's the unhandled part of the EG) */
@@ -3722,13 +3720,10 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
}
/* Mark as artificial */
UNSET_LOC(c);
- compiler_pop_fblock(c, EXCEPTION_GROUP_HANDLER, NULL);
- basicblock *reraise = compiler_new_block(c);
- if (!reraise) {
- return 0;
- }
+ compiler_pop_fblock(c, EXCEPTION_GROUP_HANDLER, NO_LABEL);
+ NEW_JUMP_TARGET_LABEL(c, reraise);
- compiler_use_next_block(c, reraise_star);
+ USE_LABEL(c, reraise_star);
ADDOP(c, PREP_RERAISE_STAR);
ADDOP_I(c, COPY, 1);
ADDOP_JUMP(c, POP_JUMP_IF_NOT_NONE, reraise);
@@ -3738,16 +3733,20 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT);
ADDOP_JUMP(c, JUMP, end);
- compiler_use_next_block(c, reraise);
+
+ USE_LABEL(c, reraise);
ADDOP(c, POP_BLOCK);
ADDOP_I(c, SWAP, 2);
ADDOP(c, POP_EXCEPT);
ADDOP_I(c, RERAISE, 0);
- compiler_use_next_block(c, cleanup);
+
+ USE_LABEL(c, cleanup);
POP_EXCEPT_AND_RERAISE(c);
- compiler_use_next_block(c, orelse);
+
+ USE_LABEL(c, orelse);
VISIT_SEQ(c, stmt, s->v.TryStar.orelse);
- compiler_use_next_block(c, end);
+
+ USE_LABEL(c, end);
return 1;
}
@@ -3917,8 +3916,6 @@ compiler_from_import(struct compiler *c, stmt_ty s)
static int
compiler_assert(struct compiler *c, stmt_ty s)
{
- basicblock *end;
-
/* Always emit a warning if the test is a non-zero length tuple */
if ((s->v.Assert.test->kind == Tuple_kind &&
asdl_seq_LEN(s->v.Assert.test->v.Tuple.elts) > 0) ||
@@ -3934,9 +3931,7 @@ compiler_assert(struct compiler *c, stmt_ty s)
}
if (c->c_optimize)
return 1;
- end = compiler_new_block(c);
- if (end == NULL)
- return 0;
+ NEW_JUMP_TARGET_LABEL(c, end);
if (!compiler_jump_if(c, s->v.Assert.test, end, 1))
return 0;
ADDOP(c, LOAD_ASSERTION_ERROR);
@@ -3945,7 +3940,8 @@ compiler_assert(struct compiler *c, stmt_ty s)
ADDOP_I(c, CALL, 0);
}
ADDOP_I(c, RAISE_VARARGS, 1);
- compiler_use_next_block(c, end);
+
+ USE_LABEL(c, end);
return 1;
}
@@ -4243,7 +4239,6 @@ compiler_nameop(struct compiler *c, identifier name, expr_context_ty ctx)
static int
compiler_boolop(struct compiler *c, expr_ty e)
{
- basicblock *end;
int jumpi;
Py_ssize_t i, n;
asdl_expr_seq *s;
@@ -4253,23 +4248,20 @@ compiler_boolop(struct compiler *c, expr_ty e)
jumpi = JUMP_IF_FALSE_OR_POP;
else
jumpi = JUMP_IF_TRUE_OR_POP;
- end = compiler_new_block(c);
- if (end == NULL)
- return 0;
+ NEW_JUMP_TARGET_LABEL(c, end);
s = e->v.BoolOp.values;
n = asdl_seq_LEN(s) - 1;
assert(n >= 0);
for (i = 0; i < n; ++i) {
VISIT(c, expr, (expr_ty)asdl_seq_GET(s, i));
ADDOP_JUMP(c, jumpi, end);
- basicblock *next = compiler_new_block(c);
- if (next == NULL) {
- return 0;
- }
- compiler_use_next_block(c, next);
+ NEW_JUMP_TARGET_LABEL(c, next);
+
+ USE_LABEL(c, next);
}
VISIT(c, expr, (expr_ty)asdl_seq_GET(s, n));
- compiler_use_next_block(c, end);
+
+ USE_LABEL(c, end);
return 1;
}
@@ -4563,9 +4555,7 @@ compiler_compare(struct compiler *c, expr_ty e)
ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, 0));
}
else {
- basicblock *cleanup = compiler_new_block(c);
- if (cleanup == NULL)
- return 0;
+ NEW_JUMP_TARGET_LABEL(c, cleanup);
for (i = 0; i < n; i++) {
VISIT(c, expr,
(expr_ty)asdl_seq_GET(e->v.Compare.comparators, i));
@@ -4576,14 +4566,14 @@ compiler_compare(struct compiler *c, expr_ty e)
}
VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n));
ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, n));
- basicblock *end = compiler_new_block(c);
- if (end == NULL)
- return 0;
+ NEW_JUMP_TARGET_LABEL(c, end);
ADDOP_JUMP_NOLINE(c, JUMP, end);
- compiler_use_next_block(c, cleanup);
+
+ USE_LABEL(c, cleanup);
ADDOP_I(c, SWAP, 2);
ADDOP(c, POP_TOP);
- compiler_use_next_block(c, end);
+
+ USE_LABEL(c, end);
}
return 1;
}
@@ -5138,16 +5128,11 @@ compiler_sync_comprehension_generator(struct compiler *c,
and then write to the element */
comprehension_ty gen;
- basicblock *start, *anchor, *if_cleanup;
Py_ssize_t i, n;
- start = compiler_new_block(c);
- if_cleanup = compiler_new_block(c);
- anchor = compiler_new_block(c);
-
- if (start == NULL || if_cleanup == NULL || anchor == NULL) {
- return 0;
- }
+ NEW_JUMP_TARGET_LABEL(c, start);
+ NEW_JUMP_TARGET_LABEL(c, if_cleanup);
+ NEW_JUMP_TARGET_LABEL(c, anchor);
gen = (comprehension_ty)asdl_seq_GET(generators, gen_index);
@@ -5176,17 +5161,17 @@ compiler_sync_comprehension_generator(struct compiler *c,
expr_ty elt = asdl_seq_GET(elts, 0);
if (elt->kind != Starred_kind) {
VISIT(c, expr, elt);
- start = NULL;
+ start = NO_LABEL;
}
}
- if (start) {
+ if (IS_LABEL(start)) {
VISIT(c, expr, gen->iter);
ADDOP(c, GET_ITER);
}
}
- if (start) {
+ if (IS_LABEL(start)) {
depth++;
- compiler_use_next_block(c, start);
+ USE_LABEL(c, start);
ADDOP_JUMP(c, FOR_ITER, anchor);
}
VISIT(c, expr, gen->target);
@@ -5233,10 +5218,12 @@ compiler_sync_comprehension_generator(struct compiler *c,
return 0;
}
}
- compiler_use_next_block(c, if_cleanup);
- if (start) {
+
+ USE_LABEL(c, if_cleanup);
+ if (IS_LABEL(start)) {
ADDOP_JUMP(c, JUMP, start);
- compiler_use_next_block(c, anchor);
+
+ USE_LABEL(c, anchor);
}
return 1;
@@ -5249,15 +5236,10 @@ compiler_async_comprehension_generator(struct compiler *c,
expr_ty elt, expr_ty val, int type)
{
comprehension_ty gen;
- basicblock *start, *if_cleanup, *except;
Py_ssize_t i, n;
- start = compiler_new_block(c);
- except = compiler_new_block(c);
- if_cleanup = compiler_new_block(c);
-
- if (start == NULL || if_cleanup == NULL || except == NULL) {
- return 0;
- }
+ NEW_JUMP_TARGET_LABEL(c, start);
+ NEW_JUMP_TARGET_LABEL(c, except);
+ NEW_JUMP_TARGET_LABEL(c, if_cleanup);
gen = (comprehension_ty)asdl_seq_GET(generators, gen_index);
@@ -5272,10 +5254,10 @@ compiler_async_comprehension_generator(struct compiler *c,
ADDOP(c, GET_AITER);
}
- compiler_use_next_block(c, start);
+ USE_LABEL(c, start);
/* Runtime will push a block here, so we need to account for that */
if (!compiler_push_fblock(c, ASYNC_COMPREHENSION_GENERATOR, start,
- NULL, NULL)) {
+ NO_LABEL, NULL)) {
return 0;
}
@@ -5328,12 +5310,13 @@ compiler_async_comprehension_generator(struct compiler *c,
return 0;
}
}
- compiler_use_next_block(c, if_cleanup);
+
+ USE_LABEL(c, if_cleanup);
ADDOP_JUMP(c, JUMP, start);
compiler_pop_fblock(c, ASYNC_COMPREHENSION_GENERATOR, start);
- compiler_use_next_block(c, except);
+ USE_LABEL(c, except);
//UNSET_LOC(c);
ADDOP(c, END_ASYNC_FOR);
@@ -5494,28 +5477,25 @@ compiler_visit_keyword(struct compiler *c, keyword_ty k)
static int
-compiler_with_except_finish(struct compiler *c, basicblock * cleanup) {
+compiler_with_except_finish(struct compiler *c, jump_target_label cleanup) {
UNSET_LOC(c);
- basicblock *suppress = compiler_new_block(c);
- if (suppress == NULL) {
- return 0;
- }
+ NEW_JUMP_TARGET_LABEL(c, suppress);
ADDOP_JUMP(c, POP_JUMP_IF_TRUE, suppress);
ADDOP_I(c, RERAISE, 2);
- compiler_use_next_block(c, suppress);
+
+ USE_LABEL(c, suppress);
ADDOP(c, POP_TOP); /* exc_value */
ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT);
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
- basicblock *exit = compiler_new_block(c);
- if (exit == NULL) {
- return 0;
- }
+ NEW_JUMP_TARGET_LABEL(c, exit);
ADDOP_JUMP(c, JUMP, exit);
- compiler_use_next_block(c, cleanup);
+
+ USE_LABEL(c, cleanup);
POP_EXCEPT_AND_RERAISE(c);
- compiler_use_next_block(c, exit);
+
+ USE_LABEL(c, exit);
return 1;
}
@@ -5546,7 +5526,6 @@ compiler_with_except_finish(struct compiler *c, basicblock * cleanup) {
static int
compiler_async_with(struct compiler *c, stmt_ty s, int pos)
{
- basicblock *block, *final, *exit, *cleanup;
withitem_ty item = asdl_seq_GET(s->v.AsyncWith.items, pos);
assert(s->kind == AsyncWith_kind);
@@ -5556,12 +5535,10 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
return compiler_error(c, "'async with' outside async function");
}
- block = compiler_new_block(c);
- final = compiler_new_block(c);
- exit = compiler_new_block(c);
- cleanup = compiler_new_block(c);
- if (!block || !final || !exit || !cleanup)
- return 0;
+ NEW_JUMP_TARGET_LABEL(c, block);
+ NEW_JUMP_TARGET_LABEL(c, final);
+ NEW_JUMP_TARGET_LABEL(c, exit);
+ NEW_JUMP_TARGET_LABEL(c, cleanup);
/* Evaluate EXPR */
VISIT(c, expr, item->context_expr);
@@ -5574,7 +5551,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
ADDOP_JUMP(c, SETUP_WITH, final);
/* SETUP_WITH pushes a finally block. */
- compiler_use_next_block(c, block);
+ USE_LABEL(c, block);
if (!compiler_push_fblock(c, ASYNC_WITH, block, final, s)) {
return 0;
}
@@ -5613,7 +5590,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
ADDOP_JUMP(c, JUMP, exit);
/* For exceptional outcome: */
- compiler_use_next_block(c, final);
+ USE_LABEL(c, final);
ADDOP_JUMP(c, SETUP_CLEANUP, cleanup);
ADDOP(c, PUSH_EXC_INFO);
@@ -5623,7 +5600,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
ADD_YIELD_FROM(c, 1);
compiler_with_except_finish(c, cleanup);
- compiler_use_next_block(c, exit);
+ USE_LABEL(c, exit);
return 1;
}
@@ -5652,17 +5629,14 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
static int
compiler_with(struct compiler *c, stmt_ty s, int pos)
{
- basicblock *block, *final, *exit, *cleanup;
withitem_ty item = asdl_seq_GET(s->v.With.items, pos);
assert(s->kind == With_kind);
- block = compiler_new_block(c);
- final = compiler_new_block(c);
- exit = compiler_new_block(c);
- cleanup = compiler_new_block(c);
- if (!block || !final || !exit || !cleanup)
- return 0;
+ NEW_JUMP_TARGET_LABEL(c, block);
+ NEW_JUMP_TARGET_LABEL(c, final);
+ NEW_JUMP_TARGET_LABEL(c, exit);
+ NEW_JUMP_TARGET_LABEL(c, cleanup);
/* Evaluate EXPR */
VISIT(c, expr, item->context_expr);
@@ -5671,7 +5645,7 @@ compiler_with(struct compiler *c, stmt_ty s, int pos)
ADDOP_JUMP(c, SETUP_WITH, final);
/* SETUP_WITH pushes a finally block. */
- compiler_use_next_block(c, block);
+ USE_LABEL(c, block);
if (!compiler_push_fblock(c, WITH, block, final, s)) {
return 0;
}
@@ -5709,14 +5683,14 @@ compiler_with(struct compiler *c, stmt_ty s, int pos)
ADDOP_JUMP(c, JUMP, exit);
/* For exceptional outcome: */
- compiler_use_next_block(c, final);
+ USE_LABEL(c, final);
ADDOP_JUMP(c, SETUP_CLEANUP, cleanup);
ADDOP(c, PUSH_EXC_INFO);
ADDOP(c, WITH_EXCEPT_START);
compiler_with_except_finish(c, cleanup);
- compiler_use_next_block(c, exit);
+ USE_LABEL(c, exit);
return 1;
}
@@ -6243,16 +6217,15 @@ ensure_fail_pop(struct compiler *c, pattern_context *pc, Py_ssize_t n)
if (size <= pc->fail_pop_size) {
return 1;
}
- Py_ssize_t needed = sizeof(basicblock*) * size;
- basicblock **resized = PyObject_Realloc(pc->fail_pop, needed);
+ Py_ssize_t needed = sizeof(jump_target_label) * size;
+ jump_target_label *resized = PyObject_Realloc(pc->fail_pop, needed);
if (resized == NULL) {
PyErr_NoMemory();
return 0;
}
pc->fail_pop = resized;
while (pc->fail_pop_size < size) {
- basicblock *new_block;
- RETURN_IF_FALSE(new_block = compiler_new_block(c));
+ NEW_JUMP_TARGET_LABEL(c, new_block);
pc->fail_pop[pc->fail_pop_size++] = new_block;
}
return 1;
@@ -6279,7 +6252,7 @@ emit_and_reset_fail_pop(struct compiler *c, pattern_context *pc)
return 1;
}
while (--pc->fail_pop_size) {
- compiler_use_next_block(c, pc->fail_pop[pc->fail_pop_size]);
+ USE_LABEL(c, pc->fail_pop[pc->fail_pop_size]);
if (!cfg_builder_addop_noarg(CFG_BUILDER(c), POP_TOP, COMPILER_LOC(c))) {
pc->fail_pop_size = 0;
PyObject_Free(pc->fail_pop);
@@ -6287,7 +6260,7 @@ emit_and_reset_fail_pop(struct compiler *c, pattern_context *pc)
return 0;
}
}
- compiler_use_next_block(c, pc->fail_pop[0]);
+ USE_LABEL(c, pc->fail_pop[0]);
PyObject_Free(pc->fail_pop);
pc->fail_pop = NULL;
return 1;
@@ -6689,8 +6662,7 @@ static int
compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc)
{
assert(p->kind == MatchOr_kind);
- basicblock *end;
- RETURN_IF_FALSE(end = compiler_new_block(c));
+ NEW_JUMP_TARGET_LABEL(c, end);
Py_ssize_t size = asdl_seq_LEN(p->v.MatchOr.patterns);
assert(size > 1);
// We're going to be messing with pc. Keep the original info handy:
@@ -6793,7 +6765,8 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc)
if (!cfg_builder_addop_noarg(CFG_BUILDER(c), POP_TOP, COMPILER_LOC(c)) || !jump_to_fail_pop(c, pc, JUMP)) {
goto error;
}
- compiler_use_next_block(c, end);
+
+ USE_LABEL(c, end);
Py_ssize_t nstores = PyList_GET_SIZE(control);
// There's a bunch of stuff on the stack between where the new stores
// are and where they need to be:
@@ -6952,8 +6925,7 @@ static int
compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc)
{
VISIT(c, expr, s->v.Match.subject);
- basicblock *end;
- RETURN_IF_FALSE(end = compiler_new_block(c));
+ NEW_JUMP_TARGET_LABEL(c, end);
Py_ssize_t cases = asdl_seq_LEN(s->v.Match.cases);
assert(cases > 0);
match_case_ty m = asdl_seq_GET(s->v.Match.cases, cases - 1);
@@ -7022,7 +6994,7 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc)
}
VISIT_SEQ(c, stmt, m->body);
}
- compiler_use_next_block(c, end);
+ USE_LABEL(c, end);
return 1;
}
@@ -7438,11 +7410,17 @@ push_cold_blocks_to_end(cfg_builder *g, int code_flags) {
if (explicit_jump == NULL) {
return -1;
}
- basicblock_addop(explicit_jump, JUMP, 0, b->b_next, NO_LOCATION);
-
+ jump_target_label next_label = {b->b_next->b_label, b->b_next};
+ basicblock_addop(explicit_jump, JUMP, 0, next_label, NO_LOCATION);
explicit_jump->b_cold = 1;
explicit_jump->b_next = b->b_next;
b->b_next = explicit_jump;
+
+ /* calculate target from target_label */
+ /* TODO: formalize an API for adding jumps in the backend */
+ struct instr *last = basicblock_last_instr(explicit_jump);
+ last->i_target = last->i_target_label.block;
+ last->i_target_label = NO_LABEL;
}
}
@@ -8262,8 +8240,8 @@ static void
dump_basicblock(const basicblock *b)
{
const char *b_return = basicblock_returns(b) ? "return " : "";
- fprintf(stderr, "[%d %d %d %p] used: %d, depth: %d, offset: %d %s\n",
- b->b_cold, b->b_warm, BB_NO_FALLTHROUGH(b), b, b->b_iused,
+ fprintf(stderr, "%d: [%d %d %d %p] used: %d, depth: %d, offset: %d %s\n",
+ b->b_label, 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;
@@ -8280,6 +8258,9 @@ static int
normalize_basic_block(basicblock *bb);
static int
+calculate_jump_targets(basicblock *entryblock);
+
+static int
optimize_cfg(basicblock *entryblock, PyObject *consts, PyObject *const_cache);
static int
@@ -8497,7 +8478,7 @@ static void
eliminate_empty_basic_blocks(basicblock *entryblock);
-static void
+static int
remove_redundant_jumps(basicblock *entryblock) {
/* If a non-empty block ends with a jump instruction, check if the next
* non-empty block reached through normal flow control is the target
@@ -8511,6 +8492,10 @@ remove_redundant_jumps(basicblock *entryblock) {
assert(!IS_ASSEMBLER_OPCODE(b_last_instr->i_opcode));
if (b_last_instr->i_opcode == JUMP ||
b_last_instr->i_opcode == JUMP_NO_INTERRUPT) {
+ if (b_last_instr->i_target == NULL) {
+ PyErr_SetString(PyExc_SystemError, "jump with NULL target");
+ return -1;
+ }
if (b_last_instr->i_target == b->b_next) {
assert(b->b_next->b_iused);
b_last_instr->i_opcode = NOP;
@@ -8522,6 +8507,7 @@ remove_redundant_jumps(basicblock *entryblock) {
if (removed) {
eliminate_empty_basic_blocks(entryblock);
}
+ return 0;
}
static PyCodeObject *
@@ -8599,7 +8585,9 @@ assemble(struct compiler *c, int addNone)
if (consts == NULL) {
goto error;
}
-
+ if (calculate_jump_targets(entryblock)) {
+ goto error;
+ }
if (optimize_cfg(entryblock, consts, c->c_const_cache)) {
goto error;
}
@@ -8627,7 +8615,9 @@ assemble(struct compiler *c, int addNone)
goto error;
}
- remove_redundant_jumps(entryblock);
+ if (remove_redundant_jumps(entryblock) < 0) {
+ goto error;
+ }
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
clean_basic_block(b);
}
@@ -9441,6 +9431,47 @@ propagate_line_numbers(basicblock *entryblock) {
}
}
+
+/* Calculate the actual jump target from the target_label */
+static int
+calculate_jump_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;
+ }
+ }
+ size_t mapsize = sizeof(basicblock *) * (max_label + 1);
+ basicblock **label2block = (basicblock **)PyMem_Malloc(mapsize);
+ if (!label2block) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ memset(label2block, 0, mapsize);
+ for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
+ if (b->b_label >= 0) {
+ label2block[b->b_label] = b;
+ }
+ }
+ 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];
+ assert(instr->i_target == NULL);
+ if (is_jump(instr) || is_block_push(instr)) {
+ int lbl = instr->i_target_label.id;
+ assert(lbl >= 0 && lbl <= max_label);
+ instr->i_target = label2block[lbl];
+ assert(instr->i_target != NULL);
+ assert(instr->i_target->b_label == lbl);
+ }
+ instr->i_target_label = NO_LABEL;
+ }
+ }
+ PyMem_Free(label2block);
+ return 0;
+}
+
/* Perform optimizations on a control flow graph.
The consts object should still be in list form to allow new constants
to be appended.