Skip to content

Commit 1b8bb1e

Browse files
authored
GH-131729: Code-gen better liveness analysis (GH-131732)
* Rename 'defined' attribute to 'in_local' to more accurately reflect how it is used * Make death of variables explicit even for array variables. * Convert in_memory from boolean to stack offset * Don't apply liveness analysis to optimizer generated code * Fix RETURN_VALUE in optimizer
1 parent b9ca438 commit 1b8bb1e

12 files changed

+344
-399
lines changed

Include/internal/pycore_uop_metadata.h

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_generated_cases.py

+29
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,11 @@ def test_overlap(self):
285285
def test_predictions(self):
286286
input = """
287287
inst(OP1, (arg -- res)) {
288+
DEAD(arg);
288289
res = Py_None;
289290
}
290291
inst(OP3, (arg -- res)) {
292+
DEAD(arg);
291293
DEOPT_IF(xxx);
292294
res = Py_None;
293295
}
@@ -303,7 +305,9 @@ def test_predictions(self):
303305
next_instr += 1;
304306
INSTRUCTION_STATS(OP1);
305307
PREDICTED_OP1:;
308+
_PyStackRef arg;
306309
_PyStackRef res;
310+
arg = stack_pointer[-1];
307311
res = Py_None;
308312
stack_pointer[-1] = res;
309313
DISPATCH();
@@ -320,7 +324,9 @@ def test_predictions(self):
320324
next_instr += 1;
321325
INSTRUCTION_STATS(OP3);
322326
static_assert(INLINE_CACHE_ENTRIES_OP1 == 0, "incorrect cache size");
327+
_PyStackRef arg;
323328
_PyStackRef res;
329+
arg = stack_pointer[-1];
324330
if (xxx) {
325331
UPDATE_MISS_STATS(OP1);
326332
assert(_PyOpcode_Deopt[opcode] == (OP1));
@@ -336,11 +342,13 @@ def test_predictions(self):
336342
def test_sync_sp(self):
337343
input = """
338344
inst(A, (arg -- res)) {
345+
DEAD(arg);
339346
SYNC_SP();
340347
escaping_call();
341348
res = Py_None;
342349
}
343350
inst(B, (arg -- res)) {
351+
DEAD(arg);
344352
res = Py_None;
345353
SYNC_SP();
346354
escaping_call();
@@ -355,7 +363,9 @@ def test_sync_sp(self):
355363
frame->instr_ptr = next_instr;
356364
next_instr += 1;
357365
INSTRUCTION_STATS(A);
366+
_PyStackRef arg;
358367
_PyStackRef res;
368+
arg = stack_pointer[-1];
359369
stack_pointer += -1;
360370
assert(WITHIN_STACK_BOUNDS());
361371
_PyFrame_SetStackPointer(frame, stack_pointer);
@@ -376,7 +386,9 @@ def test_sync_sp(self):
376386
frame->instr_ptr = next_instr;
377387
next_instr += 1;
378388
INSTRUCTION_STATS(B);
389+
_PyStackRef arg;
379390
_PyStackRef res;
391+
arg = stack_pointer[-1];
380392
res = Py_None;
381393
stack_pointer[-1] = res;
382394
_PyFrame_SetStackPointer(frame, stack_pointer);
@@ -522,6 +534,7 @@ def test_error_if_pop_with_result(self):
522534
def test_cache_effect(self):
523535
input = """
524536
inst(OP, (counter/1, extra/2, value --)) {
537+
DEAD(value);
525538
}
526539
"""
527540
output = """
@@ -535,6 +548,8 @@ def test_cache_effect(self):
535548
frame->instr_ptr = next_instr;
536549
next_instr += 4;
537550
INSTRUCTION_STATS(OP);
551+
_PyStackRef value;
552+
value = stack_pointer[-1];
538553
uint16_t counter = read_u16(&this_instr[1].cache);
539554
(void)counter;
540555
uint32_t extra = read_u32(&this_instr[2].cache);
@@ -793,6 +808,9 @@ def test_array_input(self):
793808
input = """
794809
inst(OP, (below, values[oparg*2], above --)) {
795810
SPAM(values, oparg);
811+
DEAD(below);
812+
DEAD(values);
813+
DEAD(above);
796814
}
797815
"""
798816
output = """
@@ -804,8 +822,12 @@ def test_array_input(self):
804822
frame->instr_ptr = next_instr;
805823
next_instr += 1;
806824
INSTRUCTION_STATS(OP);
825+
_PyStackRef below;
807826
_PyStackRef *values;
827+
_PyStackRef above;
828+
above = stack_pointer[-1];
808829
values = &stack_pointer[-1 - oparg*2];
830+
below = stack_pointer[-2 - oparg*2];
809831
SPAM(values, oparg);
810832
stack_pointer += -2 - oparg*2;
811833
assert(WITHIN_STACK_BOUNDS());
@@ -879,6 +901,8 @@ def test_array_input_output(self):
879901
def test_array_error_if(self):
880902
input = """
881903
inst(OP, (extra, values[oparg] --)) {
904+
DEAD(extra);
905+
DEAD(values);
882906
ERROR_IF(oparg == 0, somewhere);
883907
}
884908
"""
@@ -891,6 +915,10 @@ def test_array_error_if(self):
891915
frame->instr_ptr = next_instr;
892916
next_instr += 1;
893917
INSTRUCTION_STATS(OP);
918+
_PyStackRef extra;
919+
_PyStackRef *values;
920+
values = &stack_pointer[-oparg];
921+
extra = stack_pointer[-1 - oparg];
894922
if (oparg == 0) {
895923
stack_pointer += -1 - oparg;
896924
assert(WITHIN_STACK_BOUNDS());
@@ -1056,6 +1084,7 @@ def test_array_of_one(self):
10561084
input = """
10571085
inst(OP, (arg[1] -- out[1])) {
10581086
out[0] = arg[0];
1087+
DEAD(arg);
10591088
}
10601089
"""
10611090
output = """

Python/bytecodes.c

+25-14
Original file line numberDiff line numberDiff line change
@@ -1927,6 +1927,7 @@ dummy_func(
19271927
PyStackRef_CLOSE(value);
19281928
}
19291929
}
1930+
DEAD(values);
19301931
if (err) {
19311932
Py_DECREF(set_o);
19321933
ERROR_IF(true, error);
@@ -3583,15 +3584,15 @@ dummy_func(
35833584
#endif /* ENABLE_SPECIALIZATION_FT */
35843585
}
35853586

3586-
op(_MAYBE_EXPAND_METHOD, (callable[1], self_or_null[1], args[oparg] -- func[1], maybe_self[1], args[oparg])) {
3587+
op(_MAYBE_EXPAND_METHOD, (callable[1], self_or_null[1], args[oparg] -- callable[1], self_or_null[1], args[oparg])) {
35873588
(void)args;
35883589
if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) {
35893590
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]);
35903591
PyObject *self = ((PyMethodObject *)callable_o)->im_self;
3591-
maybe_self[0] = PyStackRef_FromPyObjectNew(self);
3592+
self_or_null[0] = PyStackRef_FromPyObjectNew(self);
35923593
PyObject *method = ((PyMethodObject *)callable_o)->im_func;
35933594
_PyStackRef temp = callable[0];
3594-
func[0] = PyStackRef_FromPyObjectNew(method);
3595+
callable[0] = PyStackRef_FromPyObjectNew(method);
35953596
PyStackRef_CLOSE(temp);
35963597
}
35973598
}
@@ -3618,6 +3619,9 @@ dummy_func(
36183619
tstate, callable[0], locals,
36193620
arguments, total_args, NULL, frame
36203621
);
3622+
DEAD(args);
3623+
DEAD(self_or_null);
3624+
DEAD(callable);
36213625
// Manipulate stack directly since we leave using DISPATCH_INLINED().
36223626
SYNC_SP();
36233627
// The frame has stolen all the arguments from the stack,
@@ -3950,10 +3954,10 @@ dummy_func(
39503954
_CALL_TUPLE_1 +
39513955
_CHECK_PERIODIC;
39523956

3953-
op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable[1], null[1], args[oparg] -- init[1], self[1], args[oparg])) {
3957+
op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable[1], self_or_null[1], args[oparg] -- callable[1], self_or_null[1], args[oparg])) {
39543958
(void)args;
39553959
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]);
3956-
DEOPT_IF(!PyStackRef_IsNull(null[0]));
3960+
DEOPT_IF(!PyStackRef_IsNull(self_or_null[0]));
39573961
DEOPT_IF(!PyType_Check(callable_o));
39583962
PyTypeObject *tp = (PyTypeObject *)callable_o;
39593963
DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(tp->tp_version_tag) != type_version);
@@ -3969,9 +3973,9 @@ dummy_func(
39693973
if (self_o == NULL) {
39703974
ERROR_NO_POP();
39713975
}
3972-
self[0] = PyStackRef_FromPyObjectSteal(self_o);
3976+
self_or_null[0] = PyStackRef_FromPyObjectSteal(self_o);
39733977
_PyStackRef temp = callable[0];
3974-
init[0] = PyStackRef_FromPyObjectNew(init_func);
3978+
callable[0] = PyStackRef_FromPyObjectNew(init_func);
39753979
PyStackRef_CLOSE(temp);
39763980
}
39773981

@@ -3982,10 +3986,11 @@ dummy_func(
39823986
assert(_PyFrame_GetBytecode(shim)[1].op.code == RETURN_VALUE);
39833987
/* Push self onto stack of shim */
39843988
shim->localsplus[0] = PyStackRef_DUP(self[0]);
3985-
DEAD(init);
3986-
DEAD(self);
39873989
_PyInterpreterFrame *temp = _PyEvalFramePushAndInit(
39883990
tstate, init[0], NULL, args-1, oparg+1, NULL, shim);
3991+
DEAD(init);
3992+
DEAD(self);
3993+
DEAD(args);
39893994
SYNC_SP();
39903995
if (temp == NULL) {
39913996
_PyEval_FrameClearAndPop(tstate, shim);
@@ -4187,9 +4192,9 @@ dummy_func(
41874192
res = PyStackRef_FromPyObjectSteal(res_o);
41884193
}
41894194

4190-
inst(CALL_ISINSTANCE, (unused/1, unused/2, callable[1], self_or_null[1], args[oparg] -- res)) {
4195+
inst(CALL_ISINSTANCE, (unused/1, unused/2, callable, self_or_null[1], args[oparg] -- res)) {
41914196
/* isinstance(o, o2) */
4192-
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]);
4197+
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
41934198

41944199
int total_args = oparg;
41954200
_PyStackRef *arguments = args;
@@ -4420,15 +4425,15 @@ dummy_func(
44204425
ERROR_IF(err, error);
44214426
}
44224427

4423-
op(_MAYBE_EXPAND_METHOD_KW, (callable[1], self_or_null[1], args[oparg], kwnames_in -- func[1], maybe_self[1], args[oparg], kwnames_out)) {
4428+
op(_MAYBE_EXPAND_METHOD_KW, (callable[1], self_or_null[1], args[oparg], kwnames_in -- callable[1], self_or_null[1], args[oparg], kwnames_out)) {
44244429
(void)args;
44254430
if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) {
44264431
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]);
44274432
PyObject *self = ((PyMethodObject *)callable_o)->im_self;
4428-
maybe_self[0] = PyStackRef_FromPyObjectNew(self);
4433+
self_or_null[0] = PyStackRef_FromPyObjectNew(self);
44294434
PyObject *method = ((PyMethodObject *)callable_o)->im_func;
44304435
_PyStackRef temp = callable[0];
4431-
func[0] = PyStackRef_FromPyObjectNew(method);
4436+
callable[0] = PyStackRef_FromPyObjectNew(method);
44324437
PyStackRef_CLOSE(temp);
44334438
}
44344439
kwnames_out = kwnames_in;
@@ -4458,6 +4463,9 @@ dummy_func(
44584463
tstate, callable[0], locals,
44594464
arguments, positional_args, kwnames_o, frame
44604465
);
4466+
DEAD(args);
4467+
DEAD(self_or_null);
4468+
DEAD(callable);
44614469
PyStackRef_CLOSE(kwnames);
44624470
// Sync stack explicitly since we leave using DISPATCH_INLINED().
44634471
SYNC_SP();
@@ -4525,6 +4533,9 @@ dummy_func(
45254533
PyStackRef_CLOSE(kwnames);
45264534
// The frame has stolen all the arguments from the stack,
45274535
// so there is no need to clean them up.
4536+
DEAD(args);
4537+
DEAD(self_or_null);
4538+
DEAD(callable);
45284539
SYNC_SP();
45294540
ERROR_IF(temp == NULL, error);
45304541
new_frame = temp;

0 commit comments

Comments
 (0)