Skip to content

Commit f5c6b99

Browse files
authored
GH-118910: Less boilerplate in the tier 2 optimizer (#118913)
1 parent 941eea0 commit f5c6b99

File tree

7 files changed

+275
-473
lines changed

7 files changed

+275
-473
lines changed

Include/internal/pycore_optimizer.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,9 @@ typedef struct ty_arena {
9393
} ty_arena;
9494

9595
struct _Py_UOpsContext {
96-
PyObject_HEAD
96+
char done;
97+
char out_of_space;
98+
bool contradiction;
9799
// The current "executing" frame.
98100
_Py_UOpsAbstractFrame *frame;
99101
_Py_UOpsAbstractFrame frames[MAX_ABSTRACT_FRAME_DEPTH];
@@ -121,16 +123,16 @@ extern _Py_UopsSymbol *_Py_uop_sym_new_const(_Py_UOpsContext *ctx, PyObject *con
121123
extern _Py_UopsSymbol *_Py_uop_sym_new_null(_Py_UOpsContext *ctx);
122124
extern bool _Py_uop_sym_has_type(_Py_UopsSymbol *sym);
123125
extern bool _Py_uop_sym_matches_type(_Py_UopsSymbol *sym, PyTypeObject *typ);
124-
extern bool _Py_uop_sym_set_null(_Py_UopsSymbol *sym);
125-
extern bool _Py_uop_sym_set_non_null(_Py_UopsSymbol *sym);
126-
extern bool _Py_uop_sym_set_type(_Py_UopsSymbol *sym, PyTypeObject *typ);
127-
extern bool _Py_uop_sym_set_const(_Py_UopsSymbol *sym, PyObject *const_val);
126+
extern void _Py_uop_sym_set_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym);
127+
extern void _Py_uop_sym_set_non_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym);
128+
extern void _Py_uop_sym_set_type(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, PyTypeObject *typ);
129+
extern void _Py_uop_sym_set_const(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, PyObject *const_val);
128130
extern bool _Py_uop_sym_is_bottom(_Py_UopsSymbol *sym);
129131
extern int _Py_uop_sym_truthiness(_Py_UopsSymbol *sym);
130132
extern PyTypeObject *_Py_uop_sym_get_type(_Py_UopsSymbol *sym);
131133

132134

133-
extern int _Py_uop_abstractcontext_init(_Py_UOpsContext *ctx);
135+
extern void _Py_uop_abstractcontext_init(_Py_UOpsContext *ctx);
134136
extern void _Py_uop_abstractcontext_fini(_Py_UOpsContext *ctx);
135137

136138
extern _Py_UOpsAbstractFrame *_Py_uop_frame_new(

Lib/test/test_generated_cases.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -909,7 +909,6 @@ def test_overridden_abstract_args(self):
909909
case OP2: {
910910
_Py_UopsSymbol *out;
911911
out = sym_new_not_null(ctx);
912-
if (out == NULL) goto out_of_space;
913912
stack_pointer[-1] = out;
914913
break;
915914
}
@@ -934,7 +933,6 @@ def test_no_overridden_case(self):
934933
case OP: {
935934
_Py_UopsSymbol *out;
936935
out = sym_new_not_null(ctx);
937-
if (out == NULL) goto out_of_space;
938936
stack_pointer[-1] = out;
939937
break;
940938
}

Python/optimizer_analysis.c

Lines changed: 34 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -297,20 +297,6 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
297297
INST->oparg = ARG; \
298298
INST->operand = OPERAND;
299299

300-
#define OUT_OF_SPACE_IF_NULL(EXPR) \
301-
do { \
302-
if ((EXPR) == NULL) { \
303-
goto out_of_space; \
304-
} \
305-
} while (0);
306-
307-
#define _LOAD_ATTR_NOT_NULL \
308-
do { \
309-
OUT_OF_SPACE_IF_NULL(attr = _Py_uop_sym_new_not_null(ctx)); \
310-
OUT_OF_SPACE_IF_NULL(null = _Py_uop_sym_new_null(ctx)); \
311-
} while (0);
312-
313-
314300
/* Shortened forms for convenience, used in optimizer_bytecodes.c */
315301
#define sym_is_not_null _Py_uop_sym_is_not_null
316302
#define sym_is_const _Py_uop_sym_is_const
@@ -324,10 +310,10 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
324310
#define sym_has_type _Py_uop_sym_has_type
325311
#define sym_get_type _Py_uop_sym_get_type
326312
#define sym_matches_type _Py_uop_sym_matches_type
327-
#define sym_set_null _Py_uop_sym_set_null
328-
#define sym_set_non_null _Py_uop_sym_set_non_null
329-
#define sym_set_type _Py_uop_sym_set_type
330-
#define sym_set_const _Py_uop_sym_set_const
313+
#define sym_set_null(SYM) _Py_uop_sym_set_null(ctx, SYM)
314+
#define sym_set_non_null(SYM) _Py_uop_sym_set_non_null(ctx, SYM)
315+
#define sym_set_type(SYM, TYPE) _Py_uop_sym_set_type(ctx, SYM, TYPE)
316+
#define sym_set_const(SYM, CNST) _Py_uop_sym_set_const(ctx, SYM, CNST)
331317
#define sym_is_bottom _Py_uop_sym_is_bottom
332318
#define sym_truthiness _Py_uop_sym_truthiness
333319
#define frame_new _Py_uop_frame_new
@@ -408,18 +394,20 @@ optimize_uops(
408394
_PyUOpInstruction *first_valid_check_stack = NULL;
409395
_PyUOpInstruction *corresponding_check_stack = NULL;
410396

411-
if (_Py_uop_abstractcontext_init(ctx) < 0) {
412-
goto out_of_space;
413-
}
397+
_Py_uop_abstractcontext_init(ctx);
414398
_Py_UOpsAbstractFrame *frame = _Py_uop_frame_new(ctx, co, ctx->n_consumed, 0, curr_stacklen);
415399
if (frame == NULL) {
416400
return -1;
417401
}
418402
ctx->curr_frame_depth++;
419403
ctx->frame = frame;
404+
ctx->done = false;
405+
ctx->out_of_space = false;
406+
ctx->contradiction = false;
420407

421408
_PyUOpInstruction *this_instr = NULL;
422-
for (int i = 0; i < trace_len; i++) {
409+
for (int i = 0; !ctx->done; i++) {
410+
assert(i < trace_len);
423411
this_instr = &trace[i];
424412

425413
int oparg = this_instr->oparg;
@@ -447,32 +435,22 @@ optimize_uops(
447435
ctx->frame->stack_pointer = stack_pointer;
448436
assert(STACK_LEVEL() >= 0);
449437
}
450-
Py_UNREACHABLE();
451-
452-
out_of_space:
453-
DPRINTF(3, "\n");
454-
DPRINTF(1, "Out of space in abstract interpreter\n");
455-
goto done;
456-
error:
457-
DPRINTF(3, "\n");
458-
DPRINTF(1, "Encountered error in abstract interpreter\n");
459-
if (opcode <= MAX_UOP_ID) {
460-
OPT_ERROR_IN_OPCODE(opcode);
438+
if (ctx->out_of_space) {
439+
DPRINTF(3, "\n");
440+
DPRINTF(1, "Out of space in abstract interpreter\n");
441+
}
442+
if (ctx->contradiction) {
443+
// Attempted to push a "bottom" (contradiction) symbol onto the stack.
444+
// This means that the abstract interpreter has hit unreachable code.
445+
// We *could* generate an _EXIT_TRACE or _FATAL_ERROR here, but hitting
446+
// bottom indicates type instability, so we are probably better off
447+
// retrying later.
448+
DPRINTF(3, "\n");
449+
DPRINTF(1, "Hit bottom in abstract interpreter\n");
450+
_Py_uop_abstractcontext_fini(ctx);
451+
return 0;
461452
}
462-
_Py_uop_abstractcontext_fini(ctx);
463-
return -1;
464453

465-
hit_bottom:
466-
// Attempted to push a "bottom" (contradition) symbol onto the stack.
467-
// This means that the abstract interpreter has hit unreachable code.
468-
// We *could* generate an _EXIT_TRACE or _FATAL_ERROR here, but hitting
469-
// bottom indicates type instability, so we are probably better off
470-
// retrying later.
471-
DPRINTF(3, "\n");
472-
DPRINTF(1, "Hit bottom in abstract interpreter\n");
473-
_Py_uop_abstractcontext_fini(ctx);
474-
return 0;
475-
done:
476454
/* Either reached the end or cannot optimize further, but there
477455
* would be no benefit in retrying later */
478456
_Py_uop_abstractcontext_fini(ctx);
@@ -485,6 +463,16 @@ optimize_uops(
485463
first_valid_check_stack->operand = max_space;
486464
}
487465
return trace_len;
466+
467+
error:
468+
DPRINTF(3, "\n");
469+
DPRINTF(1, "Encountered error in abstract interpreter\n");
470+
if (opcode <= MAX_UOP_ID) {
471+
OPT_ERROR_IN_OPCODE(opcode);
472+
}
473+
_Py_uop_abstractcontext_fini(ctx);
474+
return -1;
475+
488476
}
489477

490478

0 commit comments

Comments
 (0)