Skip to content

Commit 9533b40

Browse files
authored
gh-87092: compiler's codegen stage uses int jump target labels, and the target pointer is only calculated just before optimization stage (GH-95655)
1 parent 1b46d11 commit 9533b40

File tree

1 file changed

+52
-70
lines changed

1 file changed

+52
-70
lines changed

Python/compile.c

+52-70
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@
8585
(opcode) == SETUP_WITH || \
8686
(opcode) == SETUP_CLEANUP)
8787

88+
#define HAS_TARGET(opcode) \
89+
(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode))
90+
8891
/* opcodes that must be last in the basicblock */
8992
#define IS_TERMINATOR_OPCODE(opcode) \
9093
(IS_JUMP_OPCODE(opcode) || IS_SCOPE_EXIT_OPCODE(opcode))
@@ -141,33 +144,31 @@ static struct location NO_LOCATION = {-1, -1, -1, -1};
141144

142145
typedef struct jump_target_label_ {
143146
int id;
144-
struct basicblock_ *block;
145147
} jump_target_label;
146148

147-
static struct jump_target_label_ NO_LABEL = {-1, NULL};
149+
static struct jump_target_label_ NO_LABEL = {-1};
148150

149151
#define SAME_LABEL(L1, L2) ((L1).id == (L2).id)
150152
#define IS_LABEL(L) (!SAME_LABEL((L), (NO_LABEL)))
151153

152154
#define NEW_JUMP_TARGET_LABEL(C, NAME) \
153-
jump_target_label NAME = {cfg_new_label_id(CFG_BUILDER(C)), cfg_builder_new_block(CFG_BUILDER(C))}; \
155+
jump_target_label NAME = cfg_new_label(CFG_BUILDER(C)); \
154156
if (!IS_LABEL(NAME)) { \
155157
return 0; \
156158
}
157159

158-
#define USE_LABEL(C, LBL) cfg_builder_use_label(CFG_BUILDER(C), LBL)
160+
#define USE_LABEL(C, LBL) \
161+
if (cfg_builder_use_label(CFG_BUILDER(C), LBL) < 0) { \
162+
return 0; \
163+
}
159164

160165
struct instr {
161166
int i_opcode;
162167
int i_oparg;
163-
/* target block (if jump instruction) -- we temporarily have both the label
164-
and the block in the instr. The label is set by front end, and the block
165-
is calculated by backend. */
166-
jump_target_label i_target_label;
167-
struct basicblock_ *i_target;
168-
/* target block when exception is raised, should not be set by front-end. */
169-
struct basicblock_ *i_except;
170168
struct location i_loc;
169+
/* The following fields should not be set by the front-end: */
170+
struct basicblock_ *i_target; /* target block (if jump instruction) */
171+
struct basicblock_ *i_except; /* target block when exception is raised */
171172
};
172173

173174
typedef struct exceptstack {
@@ -351,12 +352,12 @@ enum {
351352
typedef struct cfg_builder_ {
352353
/* The entryblock, at which control flow begins. All blocks of the
353354
CFG are reachable through the b_next links */
354-
basicblock *cfg_entryblock;
355+
basicblock *g_entryblock;
355356
/* Pointer to the most recently allocated block. By following
356357
b_list links, you can reach all allocated blocks. */
357-
basicblock *block_list;
358+
basicblock *g_block_list;
358359
/* pointer to the block currently being constructed */
359-
basicblock *curblock;
360+
basicblock *g_curblock;
360361
/* label for the next instruction to be placed */
361362
jump_target_label g_current_label;
362363
/* next free label id */
@@ -752,7 +753,7 @@ dictbytype(PyObject *src, int scope_type, int flag, Py_ssize_t offset)
752753
static void
753754
cfg_builder_check(cfg_builder *g)
754755
{
755-
for (basicblock *block = g->block_list; block != NULL; block = block->b_list) {
756+
for (basicblock *block = g->g_block_list; block != NULL; block = block->b_list) {
756757
assert(!_PyMem_IsPtrFreed(block));
757758
if (block->b_instr != NULL) {
758759
assert(block->b_ialloc > 0);
@@ -770,7 +771,7 @@ static void
770771
cfg_builder_free(cfg_builder* g)
771772
{
772773
cfg_builder_check(g);
773-
basicblock *b = g->block_list;
774+
basicblock *b = g->g_block_list;
774775
while (b != NULL) {
775776
if (b->b_instr) {
776777
PyObject_Free((void *)b->b_instr);
@@ -867,10 +868,11 @@ compiler_set_qualname(struct compiler *c)
867868
return 1;
868869
}
869870

870-
static int
871-
cfg_new_label_id(cfg_builder *g)
871+
static jump_target_label
872+
cfg_new_label(cfg_builder *g)
872873
{
873-
return g->g_next_free_label++;
874+
jump_target_label lbl = {g->g_next_free_label++};
875+
return lbl;
874876
}
875877

876878
/* Allocate a new block and return a pointer to it.
@@ -885,8 +887,8 @@ cfg_builder_new_block(cfg_builder *g)
885887
return NULL;
886888
}
887889
/* Extend the singly linked list of blocks with new block. */
888-
b->b_list = g->block_list;
889-
g->block_list = b;
890+
b->b_list = g->g_block_list;
891+
g->g_block_list = b;
890892
b->b_label = -1;
891893
return b;
892894
}
@@ -895,8 +897,8 @@ static basicblock *
895897
cfg_builder_use_next_block(cfg_builder *g, basicblock *block)
896898
{
897899
assert(block != NULL);
898-
g->curblock->b_next = block;
899-
g->curblock = block;
900+
g->g_curblock->b_next = block;
901+
g->g_curblock = block;
900902
return block;
901903
}
902904

@@ -1282,17 +1284,12 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
12821284
*/
12831285

12841286
static int
1285-
basicblock_addop(basicblock *b, int opcode, int oparg,
1286-
jump_target_label target, struct location loc)
1287+
basicblock_addop(basicblock *b, int opcode, int oparg, struct location loc)
12871288
{
12881289
assert(IS_WITHIN_OPCODE_RANGE(opcode));
12891290
assert(!IS_ASSEMBLER_OPCODE(opcode));
1290-
assert(HAS_ARG(opcode) || oparg == 0);
1291+
assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0);
12911292
assert(0 <= oparg && oparg < (1 << 30));
1292-
assert(!IS_LABEL(target) ||
1293-
IS_JUMP_OPCODE(opcode) ||
1294-
IS_BLOCK_PUSH_OPCODE(opcode));
1295-
assert(oparg == 0 || !IS_LABEL(target));
12961293

12971294
int off = basicblock_next_instr(b);
12981295
if (off < 0) {
@@ -1301,7 +1298,6 @@ basicblock_addop(basicblock *b, int opcode, int oparg,
13011298
struct instr *i = &b->b_instr[off];
13021299
i->i_opcode = opcode;
13031300
i->i_oparg = oparg;
1304-
i->i_target_label = target;
13051301
i->i_target = NULL;
13061302
i->i_loc = loc;
13071303

@@ -1314,46 +1310,39 @@ cfg_builder_current_block_is_terminated(cfg_builder *g)
13141310
if (IS_LABEL(g->g_current_label)) {
13151311
return true;
13161312
}
1317-
struct instr *last = basicblock_last_instr(g->curblock);
1313+
struct instr *last = basicblock_last_instr(g->g_curblock);
13181314
return last && IS_TERMINATOR_OPCODE(last->i_opcode);
13191315
}
13201316

13211317
static int
13221318
cfg_builder_maybe_start_new_block(cfg_builder *g)
13231319
{
13241320
if (cfg_builder_current_block_is_terminated(g)) {
1325-
basicblock *b;
1326-
if (IS_LABEL(g->g_current_label)) {
1327-
b = g->g_current_label.block;
1328-
b->b_label = g->g_current_label.id;
1329-
g->g_current_label = NO_LABEL;
1330-
}
1331-
else {
1332-
b = cfg_builder_new_block(g);
1333-
}
1321+
basicblock *b = cfg_builder_new_block(g);
13341322
if (b == NULL) {
13351323
return -1;
13361324
}
1325+
b->b_label = g->g_current_label.id;
1326+
g->g_current_label = NO_LABEL;
13371327
cfg_builder_use_next_block(g, b);
13381328
}
13391329
return 0;
13401330
}
13411331

13421332
static int
1343-
cfg_builder_addop(cfg_builder *g, int opcode, int oparg, jump_target_label target,
1344-
struct location loc)
1333+
cfg_builder_addop(cfg_builder *g, int opcode, int oparg, struct location loc)
13451334
{
13461335
if (cfg_builder_maybe_start_new_block(g) != 0) {
13471336
return -1;
13481337
}
1349-
return basicblock_addop(g->curblock, opcode, oparg, target, loc);
1338+
return basicblock_addop(g->g_curblock, opcode, oparg, loc);
13501339
}
13511340

13521341
static int
13531342
cfg_builder_addop_noarg(cfg_builder *g, int opcode, struct location loc)
13541343
{
13551344
assert(!HAS_ARG(opcode));
1356-
return cfg_builder_addop(g, opcode, 0, NO_LABEL, loc);
1345+
return cfg_builder_addop(g, opcode, 0, loc);
13571346
}
13581347

13591348
static Py_ssize_t
@@ -1565,15 +1554,15 @@ cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, struct locatio
15651554
EXTENDED_ARG is used for 16, 24, and 32-bit arguments. */
15661555

15671556
int oparg_ = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int);
1568-
return cfg_builder_addop(g, opcode, oparg_, NO_LABEL, loc);
1557+
return cfg_builder_addop(g, opcode, oparg_, loc);
15691558
}
15701559

15711560
static int
15721561
cfg_builder_addop_j(cfg_builder *g, int opcode, jump_target_label target, struct location loc)
15731562
{
15741563
assert(IS_LABEL(target));
15751564
assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode));
1576-
return cfg_builder_addop(g, opcode, 0, target, loc);
1565+
return cfg_builder_addop(g, opcode, target.id, loc);
15771566
}
15781567

15791568

@@ -1795,11 +1784,11 @@ compiler_enter_scope(struct compiler *c, identifier name,
17951784
c->c_nestlevel++;
17961785

17971786
cfg_builder *g = CFG_BUILDER(c);
1798-
g->block_list = NULL;
1787+
g->g_block_list = NULL;
17991788
block = cfg_builder_new_block(g);
18001789
if (block == NULL)
18011790
return 0;
1802-
g->curblock = g->cfg_entryblock = block;
1791+
g->g_curblock = g->g_entryblock = block;
18031792
g->g_current_label = NO_LABEL;
18041793

18051794
if (u->u_scope_type == COMPILER_SCOPE_MODULE) {
@@ -7092,7 +7081,7 @@ stackdepth(basicblock *entryblock, int code_flags)
70927081
maxdepth = new_depth;
70937082
}
70947083
assert(depth >= 0); /* invalid code or bug in stackdepth() */
7095-
if (is_jump(instr) || is_block_push(instr)) {
7084+
if (HAS_TARGET(instr->i_opcode)) {
70967085
effect = stack_effect(instr->i_opcode, instr->i_oparg, 1);
70977086
assert(effect != PY_INVALID_STACK_EFFECT);
70987087
int target_depth = depth + effect;
@@ -7393,7 +7382,7 @@ mark_cold(basicblock *entryblock) {
73937382

73947383
static int
73957384
push_cold_blocks_to_end(cfg_builder *g, int code_flags) {
7396-
basicblock *entryblock = g->cfg_entryblock;
7385+
basicblock *entryblock = g->g_entryblock;
73977386
if (entryblock->b_next == NULL) {
73987387
/* single basicblock, no need to reorder */
73997388
return 0;
@@ -7410,17 +7399,14 @@ push_cold_blocks_to_end(cfg_builder *g, int code_flags) {
74107399
if (explicit_jump == NULL) {
74117400
return -1;
74127401
}
7413-
jump_target_label next_label = {b->b_next->b_label, b->b_next};
7414-
basicblock_addop(explicit_jump, JUMP, 0, next_label, NO_LOCATION);
7402+
basicblock_addop(explicit_jump, JUMP, b->b_next->b_label, NO_LOCATION);
74157403
explicit_jump->b_cold = 1;
74167404
explicit_jump->b_next = b->b_next;
74177405
b->b_next = explicit_jump;
74187406

7419-
/* calculate target from target_label */
7420-
/* TODO: formalize an API for adding jumps in the backend */
7407+
/* set target */
74217408
struct instr *last = basicblock_last_instr(explicit_jump);
7422-
last->i_target = last->i_target_label.block;
7423-
last->i_target_label = NO_LABEL;
7409+
last->i_target = explicit_jump->b_next;
74247410
}
74257411
}
74267412

@@ -8226,12 +8212,9 @@ dump_instr(struct instr *i)
82268212
if (HAS_ARG(i->i_opcode)) {
82278213
sprintf(arg, "arg: %d ", i->i_oparg);
82288214
}
8229-
if (is_jump(i)) {
8215+
if (HAS_TARGET(i->i_opcode)) {
82308216
sprintf(arg, "target: %p ", i->i_target);
82318217
}
8232-
if (is_block_push(i)) {
8233-
sprintf(arg, "except_target: %p ", i->i_target);
8234-
}
82358218
fprintf(stderr, "line: %d, opcode: %d %s%s%s\n",
82368219
i->i_loc.lineno, i->i_opcode, arg, jabs, jrel);
82378220
}
@@ -8524,7 +8507,7 @@ assemble(struct compiler *c, int addNone)
85248507
}
85258508

85268509
/* Make sure every block that falls off the end returns None. */
8527-
if (!basicblock_returns(CFG_BUILDER(c)->curblock)) {
8510+
if (!basicblock_returns(CFG_BUILDER(c)->g_curblock)) {
85288511
UNSET_LOC(c);
85298512
if (addNone)
85308513
ADDOP_LOAD_CONST(c, Py_None);
@@ -8546,7 +8529,7 @@ assemble(struct compiler *c, int addNone)
85468529
}
85478530

85488531
int nblocks = 0;
8549-
for (basicblock *b = CFG_BUILDER(c)->block_list; b != NULL; b = b->b_list) {
8532+
for (basicblock *b = CFG_BUILDER(c)->g_block_list; b != NULL; b = b->b_list) {
85508533
nblocks++;
85518534
}
85528535
if ((size_t)nblocks > SIZE_MAX / sizeof(basicblock *)) {
@@ -8555,7 +8538,7 @@ assemble(struct compiler *c, int addNone)
85558538
}
85568539

85578540
cfg_builder *g = CFG_BUILDER(c);
8558-
basicblock *entryblock = g->cfg_entryblock;
8541+
basicblock *entryblock = g->g_entryblock;
85598542
assert(entryblock != NULL);
85608543

85618544
/* Set firstlineno if it wasn't explicitly set. */
@@ -8974,7 +8957,7 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
89748957
struct instr *inst = &bb->b_instr[i];
89758958
int oparg = inst->i_oparg;
89768959
int nextop = i+1 < bb->b_iused ? bb->b_instr[i+1].i_opcode : 0;
8977-
if (is_jump(inst) || is_block_push(inst)) {
8960+
if (HAS_TARGET(inst->i_opcode)) {
89788961
/* Skip over empty basic blocks. */
89798962
while (inst->i_target->b_iused == 0) {
89808963
inst->i_target = inst->i_target->b_next;
@@ -9379,7 +9362,7 @@ eliminate_empty_basic_blocks(basicblock *entryblock) {
93799362
}
93809363
for (int i = 0; i < b->b_iused; i++) {
93819364
struct instr *instr = &b->b_instr[i];
9382-
if (is_jump(instr) || is_block_push(instr)) {
9365+
if (HAS_TARGET(instr->i_opcode)) {
93839366
basicblock *target = instr->i_target;
93849367
while (target->b_iused == 0) {
93859368
target = target->b_next;
@@ -9458,14 +9441,13 @@ calculate_jump_targets(basicblock *entryblock)
94589441
for (int i = 0; i < b->b_iused; i++) {
94599442
struct instr *instr = &b->b_instr[i];
94609443
assert(instr->i_target == NULL);
9461-
if (is_jump(instr) || is_block_push(instr)) {
9462-
int lbl = instr->i_target_label.id;
9444+
if (HAS_TARGET(instr->i_opcode)) {
9445+
int lbl = instr->i_oparg;
94639446
assert(lbl >= 0 && lbl <= max_label);
94649447
instr->i_target = label2block[lbl];
94659448
assert(instr->i_target != NULL);
94669449
assert(instr->i_target->b_label == lbl);
94679450
}
9468-
instr->i_target_label = NO_LABEL;
94699451
}
94709452
}
94719453
PyMem_Free(label2block);
@@ -9577,7 +9559,7 @@ duplicate_exits_without_lineno(cfg_builder *g)
95779559
{
95789560
/* Copy all exit blocks without line number that are targets of a jump.
95799561
*/
9580-
basicblock *entryblock = g->cfg_entryblock;
9562+
basicblock *entryblock = g->g_entryblock;
95819563
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
95829564
if (b->b_iused > 0 && is_jump(&b->b_instr[b->b_iused-1])) {
95839565
basicblock *target = b->b_instr[b->b_iused-1].i_target;

0 commit comments

Comments
 (0)