Skip to content

Commit beb8d52

Browse files
markshannonsrinivasreddy
authored andcommitted
pythonGH-128939: Refactor JIT optimize structs (pythonGH-128940)
1 parent 158d998 commit beb8d52

File tree

9 files changed

+811
-522
lines changed

9 files changed

+811
-522
lines changed

Include/internal/pycore_optimizer.h

Lines changed: 89 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -148,15 +148,6 @@ extern PyTypeObject _PyDefaultOptimizer_Type;
148148
extern PyTypeObject _PyUOpExecutor_Type;
149149
extern PyTypeObject _PyUOpOptimizer_Type;
150150

151-
/* Symbols */
152-
/* See explanation in optimizer_symbols.c */
153-
154-
struct _Py_UopsSymbol {
155-
int flags; // 0 bits: Top; 2 or more bits: Bottom
156-
PyTypeObject *typ; // Borrowed reference
157-
PyObject *const_val; // Owned reference (!)
158-
unsigned int type_version; // currently stores type version
159-
};
160151

161152
#define UOP_FORMAT_TARGET 0
162153
#define UOP_FORMAT_JUMP 1
@@ -193,27 +184,74 @@ static inline uint16_t uop_get_error_target(const _PyUOpInstruction *inst)
193184
// handle before rejoining the rest of the program.
194185
#define MAX_CHAIN_DEPTH 4
195186

196-
typedef struct _Py_UopsSymbol _Py_UopsSymbol;
187+
/* Symbols */
188+
/* See explanation in optimizer_symbols.c */
189+
190+
191+
typedef enum _JitSymType {
192+
JIT_SYM_UNKNOWN_TAG = 1,
193+
JIT_SYM_NULL_TAG = 2,
194+
JIT_SYM_NON_NULL_TAG = 3,
195+
JIT_SYM_BOTTOM_TAG = 4,
196+
JIT_SYM_TYPE_VERSION_TAG = 5,
197+
JIT_SYM_KNOWN_CLASS_TAG = 6,
198+
JIT_SYM_KNOWN_VALUE_TAG = 7,
199+
JIT_SYM_TUPLE_TAG = 8,
200+
} JitSymType;
201+
202+
typedef struct _jit_opt_known_class {
203+
uint8_t tag;
204+
uint32_t version;
205+
PyTypeObject *type;
206+
} JitOptKnownClass;
207+
208+
typedef struct _jit_opt_known_version {
209+
uint8_t tag;
210+
uint32_t version;
211+
} JitOptKnownVersion;
212+
213+
typedef struct _jit_opt_known_value {
214+
uint8_t tag;
215+
PyObject *value;
216+
} JitOptKnownValue;
217+
218+
#define MAX_SYMBOLIC_TUPLE_SIZE 7
219+
220+
typedef struct _jit_opt_tuple {
221+
uint8_t tag;
222+
uint8_t length;
223+
uint16_t items[MAX_SYMBOLIC_TUPLE_SIZE];
224+
} JitOptTuple;
225+
226+
typedef union _jit_opt_symbol {
227+
uint8_t tag;
228+
JitOptKnownClass cls;
229+
JitOptKnownValue value;
230+
JitOptKnownVersion version;
231+
JitOptTuple tuple;
232+
} JitOptSymbol;
233+
234+
197235

198236
struct _Py_UOpsAbstractFrame {
199237
// Max stacklen
200238
int stack_len;
201239
int locals_len;
202240

203-
_Py_UopsSymbol **stack_pointer;
204-
_Py_UopsSymbol **stack;
205-
_Py_UopsSymbol **locals;
241+
JitOptSymbol **stack_pointer;
242+
JitOptSymbol **stack;
243+
JitOptSymbol **locals;
206244
};
207245

208246
typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame;
209247

210248
typedef struct ty_arena {
211249
int ty_curr_number;
212250
int ty_max_number;
213-
_Py_UopsSymbol arena[TY_ARENA_SIZE];
251+
JitOptSymbol arena[TY_ARENA_SIZE];
214252
} ty_arena;
215253

216-
struct _Py_UOpsContext {
254+
typedef struct _JitOptContext {
217255
char done;
218256
char out_of_space;
219257
bool contradiction;
@@ -225,46 +263,47 @@ struct _Py_UOpsContext {
225263
// Arena for the symbolic types.
226264
ty_arena t_arena;
227265

228-
_Py_UopsSymbol **n_consumed;
229-
_Py_UopsSymbol **limit;
230-
_Py_UopsSymbol *locals_and_stack[MAX_ABSTRACT_INTERP_SIZE];
231-
};
232-
233-
typedef struct _Py_UOpsContext _Py_UOpsContext;
234-
235-
extern bool _Py_uop_sym_is_null(_Py_UopsSymbol *sym);
236-
extern bool _Py_uop_sym_is_not_null(_Py_UopsSymbol *sym);
237-
extern bool _Py_uop_sym_is_const(_Py_UopsSymbol *sym);
238-
extern PyObject *_Py_uop_sym_get_const(_Py_UopsSymbol *sym);
239-
extern _Py_UopsSymbol *_Py_uop_sym_new_unknown(_Py_UOpsContext *ctx);
240-
extern _Py_UopsSymbol *_Py_uop_sym_new_not_null(_Py_UOpsContext *ctx);
241-
extern _Py_UopsSymbol *_Py_uop_sym_new_type(
242-
_Py_UOpsContext *ctx, PyTypeObject *typ);
243-
extern _Py_UopsSymbol *_Py_uop_sym_new_const(_Py_UOpsContext *ctx, PyObject *const_val);
244-
extern _Py_UopsSymbol *_Py_uop_sym_new_null(_Py_UOpsContext *ctx);
245-
extern bool _Py_uop_sym_has_type(_Py_UopsSymbol *sym);
246-
extern bool _Py_uop_sym_matches_type(_Py_UopsSymbol *sym, PyTypeObject *typ);
247-
extern bool _Py_uop_sym_matches_type_version(_Py_UopsSymbol *sym, unsigned int version);
248-
extern void _Py_uop_sym_set_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym);
249-
extern void _Py_uop_sym_set_non_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym);
250-
extern void _Py_uop_sym_set_type(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, PyTypeObject *typ);
251-
extern bool _Py_uop_sym_set_type_version(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, unsigned int version);
252-
extern void _Py_uop_sym_set_const(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, PyObject *const_val);
253-
extern bool _Py_uop_sym_is_bottom(_Py_UopsSymbol *sym);
254-
extern int _Py_uop_sym_truthiness(_Py_UopsSymbol *sym);
255-
extern PyTypeObject *_Py_uop_sym_get_type(_Py_UopsSymbol *sym);
256-
257-
258-
extern void _Py_uop_abstractcontext_init(_Py_UOpsContext *ctx);
259-
extern void _Py_uop_abstractcontext_fini(_Py_UOpsContext *ctx);
266+
JitOptSymbol **n_consumed;
267+
JitOptSymbol **limit;
268+
JitOptSymbol *locals_and_stack[MAX_ABSTRACT_INTERP_SIZE];
269+
} JitOptContext;
270+
271+
extern bool _Py_uop_sym_is_null(JitOptSymbol *sym);
272+
extern bool _Py_uop_sym_is_not_null(JitOptSymbol *sym);
273+
extern bool _Py_uop_sym_is_const(JitOptSymbol *sym);
274+
extern PyObject *_Py_uop_sym_get_const(JitOptSymbol *sym);
275+
extern JitOptSymbol *_Py_uop_sym_new_unknown(JitOptContext *ctx);
276+
extern JitOptSymbol *_Py_uop_sym_new_not_null(JitOptContext *ctx);
277+
extern JitOptSymbol *_Py_uop_sym_new_type(
278+
JitOptContext *ctx, PyTypeObject *typ);
279+
extern JitOptSymbol *_Py_uop_sym_new_const(JitOptContext *ctx, PyObject *const_val);
280+
extern JitOptSymbol *_Py_uop_sym_new_null(JitOptContext *ctx);
281+
extern bool _Py_uop_sym_has_type(JitOptSymbol *sym);
282+
extern bool _Py_uop_sym_matches_type(JitOptSymbol *sym, PyTypeObject *typ);
283+
extern bool _Py_uop_sym_matches_type_version(JitOptSymbol *sym, unsigned int version);
284+
extern void _Py_uop_sym_set_null(JitOptContext *ctx, JitOptSymbol *sym);
285+
extern void _Py_uop_sym_set_non_null(JitOptContext *ctx, JitOptSymbol *sym);
286+
extern void _Py_uop_sym_set_type(JitOptContext *ctx, JitOptSymbol *sym, PyTypeObject *typ);
287+
extern bool _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptSymbol *sym, unsigned int version);
288+
extern void _Py_uop_sym_set_const(JitOptContext *ctx, JitOptSymbol *sym, PyObject *const_val);
289+
extern bool _Py_uop_sym_is_bottom(JitOptSymbol *sym);
290+
extern int _Py_uop_sym_truthiness(JitOptSymbol *sym);
291+
extern PyTypeObject *_Py_uop_sym_get_type(JitOptSymbol *sym);
292+
extern bool _Py_uop_sym_is_immortal(JitOptSymbol *sym);
293+
extern JitOptSymbol *_Py_uop_sym_new_tuple(JitOptContext *ctx, int size, JitOptSymbol **args);
294+
extern JitOptSymbol *_Py_uop_sym_tuple_getitem(JitOptContext *ctx, JitOptSymbol *sym, int item);
295+
extern int _Py_uop_sym_tuple_length(JitOptSymbol *sym);
296+
297+
extern void _Py_uop_abstractcontext_init(JitOptContext *ctx);
298+
extern void _Py_uop_abstractcontext_fini(JitOptContext *ctx);
260299

261300
extern _Py_UOpsAbstractFrame *_Py_uop_frame_new(
262-
_Py_UOpsContext *ctx,
301+
JitOptContext *ctx,
263302
PyCodeObject *co,
264303
int curr_stackentries,
265-
_Py_UopsSymbol **args,
304+
JitOptSymbol **args,
266305
int arg_len);
267-
extern int _Py_uop_frame_pop(_Py_UOpsContext *ctx);
306+
extern int _Py_uop_frame_pop(JitOptContext *ctx);
268307

269308
PyAPI_FUNC(PyObject *) _Py_uop_symbols_test(PyObject *self, PyObject *ignored);
270309

Lib/test/test_capi/test_opt.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,6 +1465,25 @@ def f(l: complex, r: complex) -> None:
14651465
with self.subTest(l=l, r=r, x=x, y=y):
14661466
script_helper.assert_python_ok("-c", s)
14671467

1468+
def test_symbols_flow_through_tuples(self):
1469+
def testfunc(n):
1470+
for _ in range(n):
1471+
a = 1
1472+
b = 2
1473+
t = a, b
1474+
x, y = t
1475+
r = x + y
1476+
return r
1477+
1478+
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
1479+
self.assertEqual(res, 3)
1480+
self.assertIsNotNone(ex)
1481+
uops = get_opnames(ex)
1482+
self.assertIn("_BINARY_OP_ADD_INT", uops)
1483+
self.assertNotIn("_GUARD_BOTH_INT", uops)
1484+
self.assertNotIn("_GUARD_NOS_INT", uops)
1485+
self.assertNotIn("_GUARD_TOS_INT", uops)
1486+
14681487
def test_decref_escapes(self):
14691488
class Convert9999ToNone:
14701489
def __del__(self):

Lib/test/test_generated_cases.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1842,16 +1842,16 @@ def test_overridden_abstract_args(self):
18421842
"""
18431843
output = """
18441844
case OP: {
1845-
_Py_UopsSymbol *arg1;
1846-
_Py_UopsSymbol *out;
1845+
JitOptSymbol *arg1;
1846+
JitOptSymbol *out;
18471847
arg1 = stack_pointer[-1];
18481848
out = EGGS(arg1);
18491849
stack_pointer[-1] = out;
18501850
break;
18511851
}
18521852
18531853
case OP2: {
1854-
_Py_UopsSymbol *out;
1854+
JitOptSymbol *out;
18551855
out = sym_new_not_null(ctx);
18561856
stack_pointer[-1] = out;
18571857
break;
@@ -1876,14 +1876,14 @@ def test_no_overridden_case(self):
18761876
"""
18771877
output = """
18781878
case OP: {
1879-
_Py_UopsSymbol *out;
1879+
JitOptSymbol *out;
18801880
out = sym_new_not_null(ctx);
18811881
stack_pointer[-1] = out;
18821882
break;
18831883
}
18841884
18851885
case OP2: {
1886-
_Py_UopsSymbol *out;
1886+
JitOptSymbol *out;
18871887
out = NULL;
18881888
stack_pointer[-1] = out;
18891889
break;

Modules/_testinternalcapi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
#include "pycore_instruction_sequence.h" // _PyInstructionSequence_New()
2828
#include "pycore_long.h" // _PyLong_Sign()
2929
#include "pycore_object.h" // _PyObject_IsFreed()
30-
#include "pycore_optimizer.h" // _Py_UopsSymbol, etc.
30+
#include "pycore_optimizer.h" // JitOptSymbol, etc.
3131
#include "pycore_pathconfig.h" // _PyPathConfig_ClearGlobal()
3232
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
3333
#include "pycore_pylifecycle.h" // _PyInterpreterConfig_AsDict()

Python/optimizer_analysis.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -368,13 +368,17 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
368368
#define sym_truthiness _Py_uop_sym_truthiness
369369
#define frame_new _Py_uop_frame_new
370370
#define frame_pop _Py_uop_frame_pop
371+
#define sym_new_tuple _Py_uop_sym_new_tuple
372+
#define sym_tuple_getitem _Py_uop_sym_tuple_getitem
373+
#define sym_tuple_length _Py_uop_sym_tuple_length
374+
#define sym_is_immortal _Py_uop_sym_is_immortal
371375

372376
static int
373377
optimize_to_bool(
374378
_PyUOpInstruction *this_instr,
375-
_Py_UOpsContext *ctx,
376-
_Py_UopsSymbol *value,
377-
_Py_UopsSymbol **result_ptr)
379+
JitOptContext *ctx,
380+
JitOptSymbol *value,
381+
JitOptSymbol **result_ptr)
378382
{
379383
if (sym_matches_type(value, &PyBool_Type)) {
380384
REPLACE_OP(this_instr, _NOP, 0, 0);
@@ -460,8 +464,8 @@ optimize_uops(
460464
)
461465
{
462466

463-
_Py_UOpsContext context;
464-
_Py_UOpsContext *ctx = &context;
467+
JitOptContext context;
468+
JitOptContext *ctx = &context;
465469
uint32_t opcode = UINT16_MAX;
466470
int curr_space = 0;
467471
int max_space = 0;
@@ -486,7 +490,7 @@ optimize_uops(
486490

487491
int oparg = this_instr->oparg;
488492
opcode = this_instr->opcode;
489-
_Py_UopsSymbol **stack_pointer = ctx->frame->stack_pointer;
493+
JitOptSymbol **stack_pointer = ctx->frame->stack_pointer;
490494

491495
#ifdef Py_DEBUG
492496
if (get_lltrace() >= 3) {

Python/optimizer_bytecodes.c

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
#define op(name, ...) /* NAME is ignored */
88

9-
typedef struct _Py_UopsSymbol _Py_UopsSymbol;
10-
typedef struct _Py_UOpsContext _Py_UOpsContext;
119
typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame;
1210

1311
/* Shortened forms for convenience */
@@ -32,13 +30,17 @@ typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame;
3230
#define sym_is_bottom _Py_uop_sym_is_bottom
3331
#define frame_new _Py_uop_frame_new
3432
#define frame_pop _Py_uop_frame_pop
33+
#define sym_new_tuple _Py_uop_sym_new_tuple
34+
#define sym_tuple_getitem _Py_uop_sym_tuple_getitem
35+
#define sym_tuple_length _Py_uop_sym_tuple_length
36+
#define sym_is_immortal _Py_uop_sym_is_immortal
3537

3638
extern int
3739
optimize_to_bool(
3840
_PyUOpInstruction *this_instr,
39-
_Py_UOpsContext *ctx,
40-
_Py_UopsSymbol *value,
41-
_Py_UopsSymbol **result_ptr);
41+
JitOptContext *ctx,
42+
JitOptSymbol *value,
43+
JitOptSymbol **result_ptr);
4244

4345
extern void
4446
eliminate_pop_guard(_PyUOpInstruction *this_instr, bool exit);
@@ -50,17 +52,17 @@ dummy_func(void) {
5052

5153
PyCodeObject *co;
5254
int oparg;
53-
_Py_UopsSymbol *flag;
54-
_Py_UopsSymbol *left;
55-
_Py_UopsSymbol *right;
56-
_Py_UopsSymbol *value;
57-
_Py_UopsSymbol *res;
58-
_Py_UopsSymbol *iter;
59-
_Py_UopsSymbol *top;
60-
_Py_UopsSymbol *bottom;
55+
JitOptSymbol *flag;
56+
JitOptSymbol *left;
57+
JitOptSymbol *right;
58+
JitOptSymbol *value;
59+
JitOptSymbol *res;
60+
JitOptSymbol *iter;
61+
JitOptSymbol *top;
62+
JitOptSymbol *bottom;
6163
_Py_UOpsAbstractFrame *frame;
6264
_Py_UOpsAbstractFrame *new_frame;
63-
_Py_UOpsContext *ctx;
65+
JitOptContext *ctx;
6466
_PyUOpInstruction *this_instr;
6567
_PyBloomFilter *dependencies;
6668
int modified;
@@ -85,7 +87,7 @@ dummy_func(void) {
8587

8688
op(_LOAD_FAST_AND_CLEAR, (-- value)) {
8789
value = GETLOCAL(oparg);
88-
_Py_UopsSymbol *temp = sym_new_null(ctx);
90+
JitOptSymbol *temp = sym_new_null(ctx);
8991
GETLOCAL(oparg) = temp;
9092
}
9193

@@ -365,7 +367,7 @@ dummy_func(void) {
365367
}
366368

367369
op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right -- )) {
368-
_Py_UopsSymbol *res;
370+
JitOptSymbol *res;
369371
if (sym_is_const(left) && sym_is_const(right) &&
370372
sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) {
371373
PyObject *temp = PyUnicode_Concat(sym_get_const(left), sym_get_const(right));
@@ -949,6 +951,22 @@ dummy_func(void) {
949951
res = sym_new_const(ctx, Py_True);
950952
}
951953

954+
op(_BUILD_TUPLE, (values[oparg] -- tup)) {
955+
tup = sym_new_tuple(ctx, oparg, values);
956+
}
957+
958+
op(_UNPACK_SEQUENCE_TWO_TUPLE, (seq -- val1, val0)) {
959+
val0 = sym_tuple_getitem(ctx, seq, 0);
960+
val1 = sym_tuple_getitem(ctx, seq, 1);
961+
}
962+
963+
op(_UNPACK_SEQUENCE_TUPLE, (seq -- values[oparg])) {
964+
for (int i = 0; i < oparg; i++) {
965+
values[i] = sym_tuple_getitem(ctx, seq, i);
966+
}
967+
}
968+
969+
952970
// END BYTECODES //
953971

954972
}

0 commit comments

Comments
 (0)