From 5186de3423fc299b2005b28b2f2daabbd57970fa Mon Sep 17 00:00:00 2001 From: Yan Yanchii Date: Mon, 10 Mar 2025 21:02:47 +0100 Subject: [PATCH 1/6] move STACK_USE_GUIDELINNE to pycore_compile.h --- Include/internal/pycore_compile.h | 9 +++++++++ Python/codegen.c | 9 --------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h index 9f0ca33892a43b..1c55b4c73e9d03 100644 --- a/Include/internal/pycore_compile.h +++ b/Include/internal/pycore_compile.h @@ -14,6 +14,15 @@ extern "C" { #include "pycore_symtable.h" // _Py_SourceLocation #include "pycore_instruction_sequence.h" +/* A soft limit for stack use, to avoid excessive + * memory use for large constants, etc. + * + * The value 30 is plucked out of thin air. + * Code that could use more stack than this is + * rare, so the exact value is unimportant. + */ +#define STACK_USE_GUIDELINE 30 + struct _arena; // Type defined in pycore_pyarena.h struct _mod; // Type defined in pycore_ast.h diff --git a/Python/codegen.c b/Python/codegen.c index 7a3f787aec0d2d..858d0358f922a1 100644 --- a/Python/codegen.c +++ b/Python/codegen.c @@ -37,15 +37,6 @@ #define COMP_SETCOMP 2 #define COMP_DICTCOMP 3 -/* A soft limit for stack use, to avoid excessive - * memory use for large constants, etc. - * - * The value 30 is plucked out of thin air. - * Code that could use more stack than this is - * rare, so the exact value is unimportant. - */ -#define STACK_USE_GUIDELINE 30 - #undef SUCCESS #undef ERROR #define SUCCESS 0 From f42824e6afb9b13167239900837e851106bd1772 Mon Sep 17 00:00:00 2001 From: Yan Yanchii Date: Mon, 10 Mar 2025 21:03:27 +0100 Subject: [PATCH 2/6] avoid creating unnecessary tuple when looking for constant sequence --- Python/flowgraph.c | 193 ++++++++++++++++++++++++++++----------------- 1 file changed, 119 insertions(+), 74 deletions(-) diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 6ba60d4312e56c..c189a927d0b923 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -1345,63 +1345,42 @@ add_const(PyObject *newconst, PyObject *consts, PyObject *const_cache) /* Walk basic block backwards starting from "start" trying to collect "size" number of - subsequent constants from instructions loading constants into new tuple ignoring NOP's in between. + subsequent instructions that load constants into instruciton array "seq" ignoring NOP's in between. + Caller must make sure that length of "seq" is sufficient to fit in at least "size" instructions. - Returns ERROR on error and sets "seq" to NULL. - Returns SUCCESS on success and sets "seq" to NULL if failed to collect requested number of constants. - Returns SUCCESS on success and sets "seq" to resulting tuple if succeeded to collect requested number of constants. + Returns boolean indicating whether succeeded to collect requested number of instructions. */ -static int -get_constant_sequence(basicblock *bb, int start, int size, - PyObject *consts, PyObject **seq) +static bool +get_const_sequence_instructions(basicblock *bb, int start, cfg_instr **seq, int size) { assert(start < bb->b_iused); - *seq = NULL; - PyObject *res = PyTuple_New((Py_ssize_t)size); - if (res == NULL) { - return ERROR; - } + assert(size >= 0); + assert(size <= STACK_USE_GUIDELINE); + for (; start >= 0 && size > 0; start--) { cfg_instr *instr = &bb->b_instr[start]; if (instr->i_opcode == NOP) { continue; } if (!loads_const(instr->i_opcode)) { - break; - } - PyObject *constant = get_const_value(instr->i_opcode, instr->i_oparg, consts); - if (constant == NULL) { - Py_DECREF(res); - return ERROR; + return false; } - PyTuple_SET_ITEM(res, --size, constant); + seq[--size] = instr; } - if (size > 0) { - Py_DECREF(res); - } - else { - *seq = res; - } - return SUCCESS; + + return size == 0; } /* - Walk basic block backwards starting from "start" and change "count" number of - non-NOP instructions to NOP's and set their location to NO_LOCATION. + Change every instruction in "instrs" NOP and set it's location to NO_LOCATION. + Caller must make sure "instrs" has at least "size" elements. */ -static void -nop_out(basicblock *bb, int start, int count) -{ - assert(start < bb->b_iused); - for (; count > 0; start--) { - assert(start >= 0); - cfg_instr *instr = &bb->b_instr[start]; - if (instr->i_opcode == NOP) { - continue; - } +static void nop_out(basicblock *bb, cfg_instr **instrs, int size) { + for (int i = 0; i < size; i++) { + cfg_instr *instr = instrs[i]; + assert(instr->i_opcode != NOP); INSTR_SET_OP0(instr, NOP); INSTR_SET_LOC(instr, NO_LOCATION); - count--; } } @@ -1437,19 +1416,39 @@ fold_tuple_of_constants(basicblock *bb, int i, PyObject *consts, PyObject *const /* Pre-conditions */ assert(PyDict_CheckExact(const_cache)); assert(PyList_CheckExact(consts)); + cfg_instr *instr = &bb->b_instr[i]; assert(instr->i_opcode == BUILD_TUPLE); + int seq_size = instr->i_oparg; - PyObject *newconst; - RETURN_IF_ERROR(get_constant_sequence(bb, i-1, seq_size, consts, &newconst)); - if (newconst == NULL) { + if (seq_size > STACK_USE_GUIDELINE) { + return SUCCESS; + } + + cfg_instr *seq[STACK_USE_GUIDELINE]; + if (!get_const_sequence_instructions(bb, i-1, seq, seq_size)) { /* not a const sequence */ return SUCCESS; } - assert(PyTuple_Size(newconst) == seq_size); - RETURN_IF_ERROR(instr_make_load_const(instr, newconst, consts, const_cache)); - nop_out(bb, i-1, seq_size); - return SUCCESS; + + PyObject *newconst = PyTuple_New((Py_ssize_t)seq_size); + if (newconst == NULL) { + return ERROR; + } + + for (int i = 0; i < seq_size; i++) { + cfg_instr *inst = seq[i]; + assert(loads_const(inst->i_opcode)); + PyObject *constant = get_const_value(inst->i_opcode, inst->i_oparg, consts); + if (constant == NULL) { + Py_DECREF(newconst); + return ERROR; + } + PyTuple_SET_ITEM(newconst, i, constant); + } + + nop_out(bb, seq, seq_size); + return instr_make_load_const(instr, newconst, consts, const_cache); } #define MIN_CONST_SEQUENCE_SIZE 3 @@ -1470,23 +1469,43 @@ optimize_lists_and_sets(basicblock *bb, int i, int nextop, { assert(PyDict_CheckExact(const_cache)); assert(PyList_CheckExact(consts)); + cfg_instr *instr = &bb->b_instr[i]; assert(instr->i_opcode == BUILD_LIST || instr->i_opcode == BUILD_SET); + bool contains_or_iter = nextop == GET_ITER || nextop == CONTAINS_OP; int seq_size = instr->i_oparg; - if (seq_size < MIN_CONST_SEQUENCE_SIZE && !contains_or_iter) { + if (seq_size > STACK_USE_GUIDELINE || + (seq_size < MIN_CONST_SEQUENCE_SIZE && !contains_or_iter)) + { return SUCCESS; } - PyObject *newconst; - RETURN_IF_ERROR(get_constant_sequence(bb, i-1, seq_size, consts, &newconst)); - if (newconst == NULL) { /* not a const sequence */ + + cfg_instr *seq[STACK_USE_GUIDELINE]; + if (!get_const_sequence_instructions(bb, i-1, seq, seq_size)) { /* not a const sequence */ if (contains_or_iter && instr->i_opcode == BUILD_LIST) { /* iterate over a tuple instead of list */ INSTR_SET_OP1(instr, BUILD_TUPLE, instr->i_oparg); } return SUCCESS; } - assert(PyTuple_Size(newconst) == seq_size); + + PyObject *newconst = PyTuple_New((Py_ssize_t)seq_size); + if (newconst == NULL) { + return ERROR; + } + + for (int i = 0; i < seq_size; i++) { + cfg_instr *inst = seq[i]; + assert(loads_const(inst->i_opcode)); + PyObject *constant = get_const_value(inst->i_opcode, inst->i_oparg, consts); + if (constant == NULL) { + Py_DECREF(newconst); + return ERROR; + } + PyTuple_SET_ITEM(newconst, i, constant); + } + if (instr->i_opcode == BUILD_SET) { PyObject *frozenset = PyFrozenSet_New(newconst); if (frozenset == NULL) { @@ -1495,9 +1514,11 @@ optimize_lists_and_sets(basicblock *bb, int i, int nextop, } Py_SETREF(newconst, frozenset); } + int index = add_const(newconst, consts, const_cache); RETURN_IF_ERROR(index); - nop_out(bb, i-1, seq_size); + nop_out(bb, seq, seq_size); + if (contains_or_iter) { INSTR_SET_OP1(instr, LOAD_CONST, index); } @@ -1696,19 +1717,34 @@ fold_const_binop(basicblock *bb, int i, PyObject *consts, PyObject *const_cache) #define BINOP_OPERAND_COUNT 2 assert(PyDict_CheckExact(const_cache)); assert(PyList_CheckExact(consts)); + cfg_instr *binop = &bb->b_instr[i]; assert(binop->i_opcode == BINARY_OP); - PyObject *pair; - RETURN_IF_ERROR(get_constant_sequence(bb, i-1, BINOP_OPERAND_COUNT, consts, &pair)); - if (pair == NULL) { + + cfg_instr *seq[BINOP_OPERAND_COUNT]; + if (!get_const_sequence_instructions(bb, i-1, seq, BINOP_OPERAND_COUNT)) { /* not a const sequence */ return SUCCESS; } - assert(PyTuple_Size(pair) == BINOP_OPERAND_COUNT); - PyObject *left = PyTuple_GET_ITEM(pair, 0); - PyObject *right = PyTuple_GET_ITEM(pair, 1); + + cfg_instr *first = seq[0]; + assert(loads_const(first->i_opcode)); + PyObject *left = get_const_value(first->i_opcode, first->i_oparg, consts); + if (left == NULL) { + return ERROR; + } + + cfg_instr *second = seq[1]; + assert(loads_const(second->i_opcode)); + PyObject *right = get_const_value(second->i_opcode, second->i_oparg, consts); + if (right == NULL) { + Py_DECREF(left); + return ERROR; + } + PyObject *newconst = eval_const_binop(left, binop->i_oparg, right); - Py_DECREF(pair); + Py_DECREF(left); + Py_DECREF(right); if (newconst == NULL) { if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) { return ERROR; @@ -1716,9 +1752,9 @@ fold_const_binop(basicblock *bb, int i, PyObject *consts, PyObject *const_cache) PyErr_Clear(); return SUCCESS; } - RETURN_IF_ERROR(instr_make_load_const(binop, newconst, consts, const_cache)); - nop_out(bb, i-1, BINOP_OPERAND_COUNT); - return SUCCESS; + + nop_out(bb, seq, BINOP_OPERAND_COUNT); + return instr_make_load_const(binop, newconst, consts, const_cache); } static PyObject * @@ -1765,17 +1801,26 @@ fold_const_unaryop(basicblock *bb, int i, PyObject *consts, PyObject *const_cach #define UNARYOP_OPERAND_COUNT 1 assert(PyDict_CheckExact(const_cache)); assert(PyList_CheckExact(consts)); - cfg_instr *instr = &bb->b_instr[i]; - PyObject *seq; - RETURN_IF_ERROR(get_constant_sequence(bb, i-1, UNARYOP_OPERAND_COUNT, consts, &seq)); - if (seq == NULL) { + cfg_instr *unaryop = &bb->b_instr[i]; + + cfg_instr *instr; + if (!get_const_sequence_instructions(bb, i - 1, &instr, UNARYOP_OPERAND_COUNT)) { /* not a const */ return SUCCESS; } - assert(PyTuple_Size(seq) == UNARYOP_OPERAND_COUNT); - PyObject *operand = PyTuple_GET_ITEM(seq, 0); - PyObject *newconst = eval_const_unaryop(operand, instr->i_opcode, instr->i_oparg); - Py_DECREF(seq); + + assert(loads_const(instr->i_opcode)); + PyObject *operand = get_const_value( + instr->i_opcode, + instr->i_oparg, + consts + ); + if (operand == NULL) { + return ERROR; + } + + PyObject *newconst = eval_const_unaryop(operand, unaryop->i_opcode, unaryop->i_oparg); + Py_DECREF(operand); if (newconst == NULL) { if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) { return ERROR; @@ -1783,12 +1828,12 @@ fold_const_unaryop(basicblock *bb, int i, PyObject *consts, PyObject *const_cach PyErr_Clear(); return SUCCESS; } - if (instr->i_opcode == UNARY_NOT) { + + if (unaryop->i_opcode == UNARY_NOT) { assert(PyBool_Check(newconst)); } - RETURN_IF_ERROR(instr_make_load_const(instr, newconst, consts, const_cache)); - nop_out(bb, i-1, UNARYOP_OPERAND_COUNT); - return SUCCESS; + nop_out(bb, &instr, UNARYOP_OPERAND_COUNT); + return instr_make_load_const(unaryop, newconst, consts, const_cache); } #define VISITED (-1) From 64eb38dc6b622c5f67cf58c471d3d134e937352b Mon Sep 17 00:00:00 2001 From: Yan Yanchii Date: Tue, 11 Mar 2025 00:54:41 +0100 Subject: [PATCH 3/6] rename get_const_sequence_instructions --- Python/flowgraph.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Python/flowgraph.c b/Python/flowgraph.c index c189a927d0b923..0329e377d57f04 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -1351,7 +1351,7 @@ add_const(PyObject *newconst, PyObject *consts, PyObject *const_cache) Returns boolean indicating whether succeeded to collect requested number of instructions. */ static bool -get_const_sequence_instructions(basicblock *bb, int start, cfg_instr **seq, int size) +get_const_instr_sequence(basicblock *bb, int start, cfg_instr **seq, int size) { assert(start < bb->b_iused); assert(size >= 0); @@ -1426,7 +1426,7 @@ fold_tuple_of_constants(basicblock *bb, int i, PyObject *consts, PyObject *const } cfg_instr *seq[STACK_USE_GUIDELINE]; - if (!get_const_sequence_instructions(bb, i-1, seq, seq_size)) { + if (!get_const_instr_sequence(bb, i-1, seq, seq_size)) { /* not a const sequence */ return SUCCESS; } @@ -1482,7 +1482,7 @@ optimize_lists_and_sets(basicblock *bb, int i, int nextop, } cfg_instr *seq[STACK_USE_GUIDELINE]; - if (!get_const_sequence_instructions(bb, i-1, seq, seq_size)) { /* not a const sequence */ + if (!get_const_instr_sequence(bb, i-1, seq, seq_size)) { /* not a const sequence */ if (contains_or_iter && instr->i_opcode == BUILD_LIST) { /* iterate over a tuple instead of list */ INSTR_SET_OP1(instr, BUILD_TUPLE, instr->i_oparg); @@ -1722,7 +1722,7 @@ fold_const_binop(basicblock *bb, int i, PyObject *consts, PyObject *const_cache) assert(binop->i_opcode == BINARY_OP); cfg_instr *seq[BINOP_OPERAND_COUNT]; - if (!get_const_sequence_instructions(bb, i-1, seq, BINOP_OPERAND_COUNT)) { + if (!get_const_instr_sequence(bb, i-1, seq, BINOP_OPERAND_COUNT)) { /* not a const sequence */ return SUCCESS; } @@ -1804,7 +1804,7 @@ fold_const_unaryop(basicblock *bb, int i, PyObject *consts, PyObject *const_cach cfg_instr *unaryop = &bb->b_instr[i]; cfg_instr *instr; - if (!get_const_sequence_instructions(bb, i - 1, &instr, UNARYOP_OPERAND_COUNT)) { + if (!get_const_instr_sequence(bb, i - 1, &instr, UNARYOP_OPERAND_COUNT)) { /* not a const */ return SUCCESS; } From 212dacc4cb32db8426dcfdc4ea6bf287beb3dac3 Mon Sep 17 00:00:00 2001 From: Yan Yanchii Date: Tue, 11 Mar 2025 15:28:59 +0100 Subject: [PATCH 4/6] address review --- Include/internal/pycore_compile.h | 2 +- Python/codegen.c | 14 ++-- Python/flowgraph.c | 112 +++++++++++++++--------------- 3 files changed, 65 insertions(+), 63 deletions(-) diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h index 1c55b4c73e9d03..b61ac8fccdca14 100644 --- a/Include/internal/pycore_compile.h +++ b/Include/internal/pycore_compile.h @@ -21,7 +21,7 @@ extern "C" { * Code that could use more stack than this is * rare, so the exact value is unimportant. */ -#define STACK_USE_GUIDELINE 30 +#define _PY_STACK_USE_GUIDELINE 30 struct _arena; // Type defined in pycore_pyarena.h struct _mod; // Type defined in pycore_ast.h diff --git a/Python/codegen.c b/Python/codegen.c index 858d0358f922a1..45e966c19b5c66 100644 --- a/Python/codegen.c +++ b/Python/codegen.c @@ -3200,7 +3200,7 @@ starunpack_helper_impl(compiler *c, location loc, int build, int add, int extend, int tuple) { Py_ssize_t n = asdl_seq_LEN(elts); - int big = n + pushed + (injected_arg ? 1 : 0) > STACK_USE_GUIDELINE; + int big = n + pushed + (injected_arg ? 1 : 0) > _PY_STACK_USE_GUIDELINE; int seen_star = 0; for (Py_ssize_t i = 0; i < n; i++) { expr_ty elt = asdl_seq_GET(elts, i); @@ -3355,7 +3355,7 @@ static int codegen_subdict(compiler *c, expr_ty e, Py_ssize_t begin, Py_ssize_t end) { Py_ssize_t i, n = end - begin; - int big = n*2 > STACK_USE_GUIDELINE; + int big = n*2 > _PY_STACK_USE_GUIDELINE; location loc = LOC(e); if (big) { ADDOP_I(c, loc, BUILD_MAP, 0); @@ -3402,7 +3402,7 @@ codegen_dict(compiler *c, expr_ty e) ADDOP_I(c, loc, DICT_UPDATE, 1); } else { - if (elements*2 > STACK_USE_GUIDELINE) { + if (elements*2 > _PY_STACK_USE_GUIDELINE) { RETURN_IF_ERROR(codegen_subdict(c, e, i - elements, i + 1)); if (have_dict) { ADDOP_I(c, loc, DICT_UPDATE, 1); @@ -3743,7 +3743,7 @@ maybe_optimize_method_call(compiler *c, expr_ty e) /* Check that there aren't too many arguments */ argsl = asdl_seq_LEN(args); kwdsl = asdl_seq_LEN(kwds); - if (argsl + kwdsl + (kwdsl != 0) >= STACK_USE_GUIDELINE) { + if (argsl + kwdsl + (kwdsl != 0) >= _PY_STACK_USE_GUIDELINE) { return 0; } /* Check that there are no *varargs types of arguments. */ @@ -3840,7 +3840,7 @@ codegen_joined_str(compiler *c, expr_ty e) { location loc = LOC(e); Py_ssize_t value_count = asdl_seq_LEN(e->v.JoinedStr.values); - if (value_count > STACK_USE_GUIDELINE) { + if (value_count > _PY_STACK_USE_GUIDELINE) { _Py_DECLARE_STR(empty, ""); ADDOP_LOAD_CONST_NEW(c, loc, Py_NewRef(&_Py_STR(empty))); ADDOP_NAME(c, loc, LOAD_METHOD, &_Py_ID(join), names); @@ -3919,7 +3919,7 @@ codegen_subkwargs(compiler *c, location loc, Py_ssize_t i, n = end - begin; keyword_ty kw; assert(n > 0); - int big = n*2 > STACK_USE_GUIDELINE; + int big = n*2 > _PY_STACK_USE_GUIDELINE; if (big) { ADDOP_I(c, NO_LOCATION, BUILD_MAP, 0); } @@ -3972,7 +3972,7 @@ codegen_call_helper_impl(compiler *c, location loc, nelts = asdl_seq_LEN(args); nkwelts = asdl_seq_LEN(keywords); - if (nelts + nkwelts*2 > STACK_USE_GUIDELINE) { + if (nelts + nkwelts*2 > _PY_STACK_USE_GUIDELINE) { goto ex_call; } for (i = 0; i < nelts; i++) { diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 0329e377d57f04..293a5c2136b0ae 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -1345,17 +1345,17 @@ add_const(PyObject *newconst, PyObject *consts, PyObject *const_cache) /* Walk basic block backwards starting from "start" trying to collect "size" number of - subsequent instructions that load constants into instruciton array "seq" ignoring NOP's in between. - Caller must make sure that length of "seq" is sufficient to fit in at least "size" instructions. + subsequent instructions that load constants into instruciton array "instrs" ignoring NOP's in between. + Caller must make sure that length of "instrs" is sufficient to fit in at least "size" instructions. Returns boolean indicating whether succeeded to collect requested number of instructions. */ static bool -get_const_instr_sequence(basicblock *bb, int start, cfg_instr **seq, int size) +get_subsequent_const_instrs(basicblock *bb, int start, cfg_instr **instrs, int size) { assert(start < bb->b_iused); assert(size >= 0); - assert(size <= STACK_USE_GUIDELINE); + assert(size <= _PY_STACK_USE_GUIDELINE); for (; start >= 0 && size > 0; start--) { cfg_instr *instr = &bb->b_instr[start]; @@ -1365,17 +1365,19 @@ get_const_instr_sequence(basicblock *bb, int start, cfg_instr **seq, int size) if (!loads_const(instr->i_opcode)) { return false; } - seq[--size] = instr; + instrs[--size] = instr; } return size == 0; } /* - Change every instruction in "instrs" NOP and set it's location to NO_LOCATION. + Change every instruction in "instrs" NOP and set its location to NO_LOCATION. Caller must make sure "instrs" has at least "size" elements. */ -static void nop_out(basicblock *bb, cfg_instr **instrs, int size) { +static void +nop_out(basicblock *bb, cfg_instr **instrs, int size) +{ for (int i = 0; i < size; i++) { cfg_instr *instr = instrs[i]; assert(instr->i_opcode != NOP); @@ -1421,34 +1423,34 @@ fold_tuple_of_constants(basicblock *bb, int i, PyObject *consts, PyObject *const assert(instr->i_opcode == BUILD_TUPLE); int seq_size = instr->i_oparg; - if (seq_size > STACK_USE_GUIDELINE) { + if (seq_size > _PY_STACK_USE_GUIDELINE) { return SUCCESS; } - cfg_instr *seq[STACK_USE_GUIDELINE]; - if (!get_const_instr_sequence(bb, i-1, seq, seq_size)) { + cfg_instr *const_instrs[_PY_STACK_USE_GUIDELINE]; + if (!get_subsequent_const_instrs(bb, i-1, const_instrs, seq_size)) { /* not a const sequence */ return SUCCESS; } - PyObject *newconst = PyTuple_New((Py_ssize_t)seq_size); - if (newconst == NULL) { + PyObject *const_tuple = PyTuple_New((Py_ssize_t)seq_size); + if (const_tuple == NULL) { return ERROR; } for (int i = 0; i < seq_size; i++) { - cfg_instr *inst = seq[i]; + cfg_instr *inst = const_instrs[i]; assert(loads_const(inst->i_opcode)); - PyObject *constant = get_const_value(inst->i_opcode, inst->i_oparg, consts); - if (constant == NULL) { - Py_DECREF(newconst); + PyObject *element = get_const_value(inst->i_opcode, inst->i_oparg, consts); + if (element == NULL) { + Py_DECREF(const_tuple); return ERROR; } - PyTuple_SET_ITEM(newconst, i, constant); + PyTuple_SET_ITEM(const_tuple, i, element); } - nop_out(bb, seq, seq_size); - return instr_make_load_const(instr, newconst, consts, const_cache); + nop_out(bb, const_instrs, seq_size); + return instr_make_load_const(instr, const_tuple, consts, const_cache); } #define MIN_CONST_SEQUENCE_SIZE 3 @@ -1475,14 +1477,14 @@ optimize_lists_and_sets(basicblock *bb, int i, int nextop, bool contains_or_iter = nextop == GET_ITER || nextop == CONTAINS_OP; int seq_size = instr->i_oparg; - if (seq_size > STACK_USE_GUIDELINE || + if (seq_size > _PY_STACK_USE_GUIDELINE || (seq_size < MIN_CONST_SEQUENCE_SIZE && !contains_or_iter)) { return SUCCESS; } - cfg_instr *seq[STACK_USE_GUIDELINE]; - if (!get_const_instr_sequence(bb, i-1, seq, seq_size)) { /* not a const sequence */ + cfg_instr *const_instrs[_PY_STACK_USE_GUIDELINE]; + if (!get_subsequent_const_instrs(bb, i-1, const_instrs, seq_size)) { /* not a const sequence */ if (contains_or_iter && instr->i_opcode == BUILD_LIST) { /* iterate over a tuple instead of list */ INSTR_SET_OP1(instr, BUILD_TUPLE, instr->i_oparg); @@ -1490,34 +1492,34 @@ optimize_lists_and_sets(basicblock *bb, int i, int nextop, return SUCCESS; } - PyObject *newconst = PyTuple_New((Py_ssize_t)seq_size); - if (newconst == NULL) { + PyObject *const_result = PyTuple_New((Py_ssize_t)seq_size); + if (const_result == NULL) { return ERROR; } for (int i = 0; i < seq_size; i++) { - cfg_instr *inst = seq[i]; + cfg_instr *inst = const_instrs[i]; assert(loads_const(inst->i_opcode)); - PyObject *constant = get_const_value(inst->i_opcode, inst->i_oparg, consts); - if (constant == NULL) { - Py_DECREF(newconst); + PyObject *element = get_const_value(inst->i_opcode, inst->i_oparg, consts); + if (element == NULL) { + Py_DECREF(const_result); return ERROR; } - PyTuple_SET_ITEM(newconst, i, constant); + PyTuple_SET_ITEM(const_result, i, element); } if (instr->i_opcode == BUILD_SET) { - PyObject *frozenset = PyFrozenSet_New(newconst); + PyObject *frozenset = PyFrozenSet_New(const_result); if (frozenset == NULL) { - Py_DECREF(newconst); + Py_DECREF(const_result); return ERROR; } - Py_SETREF(newconst, frozenset); + Py_SETREF(const_result, frozenset); } - int index = add_const(newconst, consts, const_cache); + int index = add_const(const_result, consts, const_cache); RETURN_IF_ERROR(index); - nop_out(bb, seq, seq_size); + nop_out(bb, const_instrs, seq_size); if (contains_or_iter) { INSTR_SET_OP1(instr, LOAD_CONST, index); @@ -1721,30 +1723,30 @@ fold_const_binop(basicblock *bb, int i, PyObject *consts, PyObject *const_cache) cfg_instr *binop = &bb->b_instr[i]; assert(binop->i_opcode == BINARY_OP); - cfg_instr *seq[BINOP_OPERAND_COUNT]; - if (!get_const_instr_sequence(bb, i-1, seq, BINOP_OPERAND_COUNT)) { + cfg_instr *operands_instrs[BINOP_OPERAND_COUNT]; + if (!get_subsequent_const_instrs(bb, i-1, operands_instrs, BINOP_OPERAND_COUNT)) { /* not a const sequence */ return SUCCESS; } - cfg_instr *first = seq[0]; - assert(loads_const(first->i_opcode)); - PyObject *left = get_const_value(first->i_opcode, first->i_oparg, consts); - if (left == NULL) { + cfg_instr *lhs_instr = operands_instrs[0]; + assert(loads_const(lhs_instr->i_opcode)); + PyObject *lhs = get_const_value(lhs_instr->i_opcode, lhs_instr->i_oparg, consts); + if (lhs == NULL) { return ERROR; } - cfg_instr *second = seq[1]; - assert(loads_const(second->i_opcode)); - PyObject *right = get_const_value(second->i_opcode, second->i_oparg, consts); - if (right == NULL) { - Py_DECREF(left); + cfg_instr *rhs_instr = operands_instrs[1]; + assert(loads_const(rhs_instr->i_opcode)); + PyObject *rhs = get_const_value(rhs_instr->i_opcode, rhs_instr->i_oparg, consts); + if (rhs == NULL) { + Py_DECREF(lhs); return ERROR; } - PyObject *newconst = eval_const_binop(left, binop->i_oparg, right); - Py_DECREF(left); - Py_DECREF(right); + PyObject *newconst = eval_const_binop(lhs, binop->i_oparg, rhs); + Py_DECREF(lhs); + Py_DECREF(rhs); if (newconst == NULL) { if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) { return ERROR; @@ -1753,7 +1755,7 @@ fold_const_binop(basicblock *bb, int i, PyObject *consts, PyObject *const_cache) return SUCCESS; } - nop_out(bb, seq, BINOP_OPERAND_COUNT); + nop_out(bb, operands_instrs, BINOP_OPERAND_COUNT); return instr_make_load_const(binop, newconst, consts, const_cache); } @@ -1803,16 +1805,16 @@ fold_const_unaryop(basicblock *bb, int i, PyObject *consts, PyObject *const_cach assert(PyList_CheckExact(consts)); cfg_instr *unaryop = &bb->b_instr[i]; - cfg_instr *instr; - if (!get_const_instr_sequence(bb, i - 1, &instr, UNARYOP_OPERAND_COUNT)) { + cfg_instr *operand_instr; + if (!get_subsequent_const_instrs(bb, i-1, &operand_instr, UNARYOP_OPERAND_COUNT)) { /* not a const */ return SUCCESS; } - assert(loads_const(instr->i_opcode)); + assert(loads_const(operand_instr->i_opcode)); PyObject *operand = get_const_value( - instr->i_opcode, - instr->i_oparg, + operand_instr->i_opcode, + operand_instr->i_oparg, consts ); if (operand == NULL) { @@ -1832,7 +1834,7 @@ fold_const_unaryop(basicblock *bb, int i, PyObject *consts, PyObject *const_cach if (unaryop->i_opcode == UNARY_NOT) { assert(PyBool_Check(newconst)); } - nop_out(bb, &instr, UNARYOP_OPERAND_COUNT); + nop_out(bb, &operand_instr, UNARYOP_OPERAND_COUNT); return instr_make_load_const(unaryop, newconst, consts, const_cache); } From bfa67f570ff59c8513aff5d4a29cfd317287b2a0 Mon Sep 17 00:00:00 2001 From: Yan Yanchii Date: Tue, 11 Mar 2025 19:49:53 +0100 Subject: [PATCH 5/6] some adjustments --- Python/flowgraph.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 293a5c2136b0ae..d93fb5474dfcd7 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -1345,7 +1345,7 @@ add_const(PyObject *newconst, PyObject *consts, PyObject *const_cache) /* Walk basic block backwards starting from "start" trying to collect "size" number of - subsequent instructions that load constants into instruciton array "instrs" ignoring NOP's in between. + subsequent instructions that load constants into instruction array "instrs" ignoring NOP's in between. Caller must make sure that length of "instrs" is sufficient to fit in at least "size" instructions. Returns boolean indicating whether succeeded to collect requested number of instructions. @@ -1376,7 +1376,7 @@ get_subsequent_const_instrs(basicblock *bb, int start, cfg_instr **instrs, int s Caller must make sure "instrs" has at least "size" elements. */ static void -nop_out(basicblock *bb, cfg_instr **instrs, int size) +nop_out(cfg_instr **instrs, int size) { for (int i = 0; i < size; i++) { cfg_instr *instr = instrs[i]; @@ -1449,7 +1449,7 @@ fold_tuple_of_constants(basicblock *bb, int i, PyObject *consts, PyObject *const PyTuple_SET_ITEM(const_tuple, i, element); } - nop_out(bb, const_instrs, seq_size); + nop_out(const_instrs, seq_size); return instr_make_load_const(instr, const_tuple, consts, const_cache); } @@ -1519,7 +1519,7 @@ optimize_lists_and_sets(basicblock *bb, int i, int nextop, int index = add_const(const_result, consts, const_cache); RETURN_IF_ERROR(index); - nop_out(bb, const_instrs, seq_size); + nop_out(const_instrs, seq_size); if (contains_or_iter) { INSTR_SET_OP1(instr, LOAD_CONST, index); @@ -1755,7 +1755,7 @@ fold_const_binop(basicblock *bb, int i, PyObject *consts, PyObject *const_cache) return SUCCESS; } - nop_out(bb, operands_instrs, BINOP_OPERAND_COUNT); + nop_out(operands_instrs, BINOP_OPERAND_COUNT); return instr_make_load_const(binop, newconst, consts, const_cache); } @@ -1834,7 +1834,7 @@ fold_const_unaryop(basicblock *bb, int i, PyObject *consts, PyObject *const_cach if (unaryop->i_opcode == UNARY_NOT) { assert(PyBool_Check(newconst)); } - nop_out(bb, &operand_instr, UNARYOP_OPERAND_COUNT); + nop_out(&operand_instr, UNARYOP_OPERAND_COUNT); return instr_make_load_const(unaryop, newconst, consts, const_cache); } From 9d3297ea236819fa97d080d5c4139841ec79d032 Mon Sep 17 00:00:00 2001 From: Yan Yanchii Date: Tue, 11 Mar 2025 22:54:28 +0100 Subject: [PATCH 6/6] address review --- Python/flowgraph.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Python/flowgraph.c b/Python/flowgraph.c index d93fb5474dfcd7..e32676847f3967 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -1344,14 +1344,14 @@ add_const(PyObject *newconst, PyObject *consts, PyObject *const_cache) } /* - Walk basic block backwards starting from "start" trying to collect "size" number of - subsequent instructions that load constants into instruction array "instrs" ignoring NOP's in between. - Caller must make sure that length of "instrs" is sufficient to fit in at least "size" instructions. + Traverse the instructions of the basic block backwards from index "start", skipping over NOPs. + Try to collect "size" number of consecutive instructions that load constants into the array "instrs". + Caller must make sure that length of "instrs" is sufficient to fit in at least "size" instructions. - Returns boolean indicating whether succeeded to collect requested number of instructions. + Return boolean indicating whether "size" such instructions were found. */ static bool -get_subsequent_const_instrs(basicblock *bb, int start, cfg_instr **instrs, int size) +get_const_loading_instrs(basicblock *bb, int start, cfg_instr **instrs, int size) { assert(start < bb->b_iused); assert(size >= 0); @@ -1428,7 +1428,7 @@ fold_tuple_of_constants(basicblock *bb, int i, PyObject *consts, PyObject *const } cfg_instr *const_instrs[_PY_STACK_USE_GUIDELINE]; - if (!get_subsequent_const_instrs(bb, i-1, const_instrs, seq_size)) { + if (!get_const_loading_instrs(bb, i-1, const_instrs, seq_size)) { /* not a const sequence */ return SUCCESS; } @@ -1484,7 +1484,7 @@ optimize_lists_and_sets(basicblock *bb, int i, int nextop, } cfg_instr *const_instrs[_PY_STACK_USE_GUIDELINE]; - if (!get_subsequent_const_instrs(bb, i-1, const_instrs, seq_size)) { /* not a const sequence */ + if (!get_const_loading_instrs(bb, i-1, const_instrs, seq_size)) { /* not a const sequence */ if (contains_or_iter && instr->i_opcode == BUILD_LIST) { /* iterate over a tuple instead of list */ INSTR_SET_OP1(instr, BUILD_TUPLE, instr->i_oparg); @@ -1724,7 +1724,7 @@ fold_const_binop(basicblock *bb, int i, PyObject *consts, PyObject *const_cache) assert(binop->i_opcode == BINARY_OP); cfg_instr *operands_instrs[BINOP_OPERAND_COUNT]; - if (!get_subsequent_const_instrs(bb, i-1, operands_instrs, BINOP_OPERAND_COUNT)) { + if (!get_const_loading_instrs(bb, i-1, operands_instrs, BINOP_OPERAND_COUNT)) { /* not a const sequence */ return SUCCESS; } @@ -1806,7 +1806,7 @@ fold_const_unaryop(basicblock *bb, int i, PyObject *consts, PyObject *const_cach cfg_instr *unaryop = &bb->b_instr[i]; cfg_instr *operand_instr; - if (!get_subsequent_const_instrs(bb, i-1, &operand_instr, UNARYOP_OPERAND_COUNT)) { + if (!get_const_loading_instrs(bb, i-1, &operand_instr, UNARYOP_OPERAND_COUNT)) { /* not a const */ return SUCCESS; } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy