From c5fdb9628200e8bae3c51a518c8d9904736a36a0 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 20 Mar 2025 09:15:19 +0000 Subject: [PATCH 1/4] Remove _PyOpcode_max_stack_effect as it is no longer used --- Include/internal/pycore_opcode_metadata.h | 959 ------------------ Python/flowgraph.c | 3 - .../opcode_metadata_generator.py | 95 -- 3 files changed, 1057 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 152238d21e5da7..096cd0b5e8db67 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -981,965 +981,6 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { #endif -extern int _PyOpcode_max_stack_effect(int opcode, int oparg, int *effect); -#ifdef NEED_OPCODE_METADATA -int _PyOpcode_max_stack_effect(int opcode, int oparg, int *effect) { - switch(opcode) { - case BINARY_OP: { - *effect = 1; - return 0; - } - case BINARY_OP_ADD_FLOAT: { - *effect = 0; - return 0; - } - case BINARY_OP_ADD_INT: { - *effect = 0; - return 0; - } - case BINARY_OP_ADD_UNICODE: { - *effect = 0; - return 0; - } - case BINARY_OP_EXTEND: { - *effect = 0; - return 0; - } - case BINARY_OP_INPLACE_ADD_UNICODE: { - *effect = 0; - return 0; - } - case BINARY_OP_MULTIPLY_FLOAT: { - *effect = 0; - return 0; - } - case BINARY_OP_MULTIPLY_INT: { - *effect = 0; - return 0; - } - case BINARY_OP_SUBSCR_DICT: { - *effect = -1; - return 0; - } - case BINARY_OP_SUBSCR_GETITEM: { - *effect = 1; - return 0; - } - case BINARY_OP_SUBSCR_LIST_INT: { - *effect = -1; - return 0; - } - case BINARY_OP_SUBSCR_STR_INT: { - *effect = -1; - return 0; - } - case BINARY_OP_SUBSCR_TUPLE_INT: { - *effect = -1; - return 0; - } - case BINARY_OP_SUBTRACT_FLOAT: { - *effect = 0; - return 0; - } - case BINARY_OP_SUBTRACT_INT: { - *effect = 0; - return 0; - } - case BINARY_SLICE: { - *effect = 0; - return 0; - } - case BUILD_LIST: { - *effect = 1 - oparg; - return 0; - } - case BUILD_MAP: { - *effect = 1 - oparg*2; - return 0; - } - case BUILD_SET: { - *effect = 1 - oparg; - return 0; - } - case BUILD_SLICE: { - *effect = 1 - oparg; - return 0; - } - case BUILD_STRING: { - *effect = 1 - oparg; - return 0; - } - case BUILD_TUPLE: { - *effect = 1 - oparg; - return 0; - } - case CACHE: { - *effect = 0; - return 0; - } - case CALL: { - int max_eff = Py_MAX(0, -1 - oparg); - max_eff = Py_MAX(max_eff, -2 - oparg); - *effect = max_eff; - return 0; - } - case CALL_ALLOC_AND_ENTER_INIT: { - int max_eff = Py_MAX(0, -1 - oparg); - max_eff = Py_MAX(max_eff, -2 - oparg); - *effect = max_eff; - return 0; - } - case CALL_BOUND_METHOD_EXACT_ARGS: { - int max_eff = Py_MAX(0, -1 - oparg); - max_eff = Py_MAX(max_eff, -2 - oparg); - *effect = max_eff; - return 0; - } - case CALL_BOUND_METHOD_GENERAL: { - int max_eff = Py_MAX(0, -1 - oparg); - max_eff = Py_MAX(max_eff, -2 - oparg); - *effect = max_eff; - return 0; - } - case CALL_BUILTIN_CLASS: { - *effect = -1 - oparg; - return 0; - } - case CALL_BUILTIN_FAST: { - *effect = -1 - oparg; - return 0; - } - case CALL_BUILTIN_FAST_WITH_KEYWORDS: { - *effect = -1 - oparg; - return 0; - } - case CALL_BUILTIN_O: { - *effect = -1 - oparg; - return 0; - } - case CALL_FUNCTION_EX: { - *effect = 0; - return 0; - } - case CALL_INTRINSIC_1: { - *effect = 0; - return 0; - } - case CALL_INTRINSIC_2: { - *effect = -1; - return 0; - } - case CALL_ISINSTANCE: { - *effect = -1 - oparg; - return 0; - } - case CALL_KW: { - int max_eff = Py_MAX(0, -2 - oparg); - max_eff = Py_MAX(max_eff, -3 - oparg); - *effect = max_eff; - return 0; - } - case CALL_KW_BOUND_METHOD: { - int max_eff = Py_MAX(0, -2 - oparg); - max_eff = Py_MAX(max_eff, -3 - oparg); - *effect = max_eff; - return 0; - } - case CALL_KW_NON_PY: { - *effect = Py_MAX(0, -2 - oparg); - return 0; - } - case CALL_KW_PY: { - int max_eff = Py_MAX(0, -2 - oparg); - max_eff = Py_MAX(max_eff, -3 - oparg); - *effect = max_eff; - return 0; - } - case CALL_LEN: { - *effect = -1 - oparg; - return 0; - } - case CALL_LIST_APPEND: { - *effect = -3; - return 0; - } - case CALL_METHOD_DESCRIPTOR_FAST: { - *effect = -1 - oparg; - return 0; - } - case CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: { - *effect = -1 - oparg; - return 0; - } - case CALL_METHOD_DESCRIPTOR_NOARGS: { - *effect = -1 - oparg; - return 0; - } - case CALL_METHOD_DESCRIPTOR_O: { - *effect = -1 - oparg; - return 0; - } - case CALL_NON_PY_GENERAL: { - *effect = Py_MAX(0, -1 - oparg); - return 0; - } - case CALL_PY_EXACT_ARGS: { - int max_eff = Py_MAX(0, -1 - oparg); - max_eff = Py_MAX(max_eff, -2 - oparg); - *effect = max_eff; - return 0; - } - case CALL_PY_GENERAL: { - int max_eff = Py_MAX(0, -1 - oparg); - max_eff = Py_MAX(max_eff, -2 - oparg); - *effect = max_eff; - return 0; - } - case CALL_STR_1: { - *effect = -2; - return 0; - } - case CALL_TUPLE_1: { - *effect = -2; - return 0; - } - case CALL_TYPE_1: { - *effect = -2; - return 0; - } - case CHECK_EG_MATCH: { - *effect = 0; - return 0; - } - case CHECK_EXC_MATCH: { - *effect = 0; - return 0; - } - case CLEANUP_THROW: { - *effect = -1; - return 0; - } - case COMPARE_OP: { - *effect = 0; - return 0; - } - case COMPARE_OP_FLOAT: { - *effect = 0; - return 0; - } - case COMPARE_OP_INT: { - *effect = 0; - return 0; - } - case COMPARE_OP_STR: { - *effect = 0; - return 0; - } - case CONTAINS_OP: { - *effect = 0; - return 0; - } - case CONTAINS_OP_DICT: { - *effect = -1; - return 0; - } - case CONTAINS_OP_SET: { - *effect = -1; - return 0; - } - case CONVERT_VALUE: { - *effect = 0; - return 0; - } - case COPY: { - *effect = 1; - return 0; - } - case COPY_FREE_VARS: { - *effect = 0; - return 0; - } - case DELETE_ATTR: { - *effect = -1; - return 0; - } - case DELETE_DEREF: { - *effect = 0; - return 0; - } - case DELETE_FAST: { - *effect = 0; - return 0; - } - case DELETE_GLOBAL: { - *effect = 0; - return 0; - } - case DELETE_NAME: { - *effect = 0; - return 0; - } - case DELETE_SUBSCR: { - *effect = -2; - return 0; - } - case DICT_MERGE: { - *effect = -1; - return 0; - } - case DICT_UPDATE: { - *effect = -1; - return 0; - } - case END_ASYNC_FOR: { - *effect = -2; - return 0; - } - case END_FOR: { - *effect = -1; - return 0; - } - case END_SEND: { - *effect = -1; - return 0; - } - case ENTER_EXECUTOR: { - *effect = 0; - return 0; - } - case EXIT_INIT_CHECK: { - *effect = -1; - return 0; - } - case EXTENDED_ARG: { - *effect = 0; - return 0; - } - case FORMAT_SIMPLE: { - *effect = 0; - return 0; - } - case FORMAT_WITH_SPEC: { - *effect = -1; - return 0; - } - case FOR_ITER: { - *effect = 1; - return 0; - } - case FOR_ITER_GEN: { - *effect = 1; - return 0; - } - case FOR_ITER_LIST: { - *effect = 1; - return 0; - } - case FOR_ITER_RANGE: { - *effect = 1; - return 0; - } - case FOR_ITER_TUPLE: { - *effect = 1; - return 0; - } - case GET_AITER: { - *effect = 0; - return 0; - } - case GET_ANEXT: { - *effect = 1; - return 0; - } - case GET_AWAITABLE: { - *effect = 0; - return 0; - } - case GET_ITER: { - *effect = 0; - return 0; - } - case GET_LEN: { - *effect = 1; - return 0; - } - case GET_YIELD_FROM_ITER: { - *effect = 0; - return 0; - } - case IMPORT_FROM: { - *effect = 1; - return 0; - } - case IMPORT_NAME: { - *effect = -1; - return 0; - } - case INSTRUMENTED_CALL: { - *effect = Py_MAX(0, -1 - oparg); - return 0; - } - case INSTRUMENTED_CALL_FUNCTION_EX: { - *effect = 0; - return 0; - } - case INSTRUMENTED_CALL_KW: { - *effect = Py_MAX(0, -2 - oparg); - return 0; - } - case INSTRUMENTED_END_ASYNC_FOR: { - *effect = 0; - return 0; - } - case INSTRUMENTED_END_FOR: { - *effect = -1; - return 0; - } - case INSTRUMENTED_END_SEND: { - *effect = -1; - return 0; - } - case INSTRUMENTED_FOR_ITER: { - *effect = 0; - return 0; - } - case INSTRUMENTED_INSTRUCTION: { - *effect = 0; - return 0; - } - case INSTRUMENTED_JUMP_BACKWARD: { - *effect = 0; - return 0; - } - case INSTRUMENTED_JUMP_FORWARD: { - *effect = 0; - return 0; - } - case INSTRUMENTED_LINE: { - *effect = 0; - return 0; - } - case INSTRUMENTED_LOAD_SUPER_ATTR: { - *effect = Py_MAX(-2, -2 + (oparg & 1)); - return 0; - } - case INSTRUMENTED_NOT_TAKEN: { - *effect = 0; - return 0; - } - case INSTRUMENTED_POP_ITER: { - *effect = -1; - return 0; - } - case INSTRUMENTED_POP_JUMP_IF_FALSE: { - *effect = 0; - return 0; - } - case INSTRUMENTED_POP_JUMP_IF_NONE: { - *effect = 0; - return 0; - } - case INSTRUMENTED_POP_JUMP_IF_NOT_NONE: { - *effect = 0; - return 0; - } - case INSTRUMENTED_POP_JUMP_IF_TRUE: { - *effect = 0; - return 0; - } - case INSTRUMENTED_RESUME: { - *effect = 0; - return 0; - } - case INSTRUMENTED_RETURN_VALUE: { - *effect = 0; - return 0; - } - case INSTRUMENTED_YIELD_VALUE: { - *effect = 0; - return 0; - } - case INTERPRETER_EXIT: { - *effect = -1; - return 0; - } - case IS_OP: { - *effect = -1; - return 0; - } - case JUMP: { - *effect = 0; - return 0; - } - case JUMP_BACKWARD: { - *effect = 0; - return 0; - } - case JUMP_BACKWARD_JIT: { - *effect = 0; - return 0; - } - case JUMP_BACKWARD_NO_INTERRUPT: { - *effect = 0; - return 0; - } - case JUMP_BACKWARD_NO_JIT: { - *effect = 0; - return 0; - } - case JUMP_FORWARD: { - *effect = 0; - return 0; - } - case JUMP_IF_FALSE: { - *effect = 0; - return 0; - } - case JUMP_IF_TRUE: { - *effect = 0; - return 0; - } - case JUMP_NO_INTERRUPT: { - *effect = 0; - return 0; - } - case LIST_APPEND: { - *effect = -1; - return 0; - } - case LIST_EXTEND: { - *effect = -1; - return 0; - } - case LOAD_ATTR: { - int max_eff = Py_MAX(1, (oparg & 1)); - max_eff = Py_MAX(max_eff, (oparg&1)); - *effect = max_eff; - return 0; - } - case LOAD_ATTR_CLASS: { - *effect = Py_MAX(0, (oparg & 1)); - return 0; - } - case LOAD_ATTR_CLASS_WITH_METACLASS_CHECK: { - *effect = Py_MAX(0, (oparg & 1)); - return 0; - } - case LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN: { - *effect = 0; - return 0; - } - case LOAD_ATTR_INSTANCE_VALUE: { - *effect = Py_MAX(0, (oparg & 1)); - return 0; - } - case LOAD_ATTR_METHOD_LAZY_DICT: { - *effect = 1; - return 0; - } - case LOAD_ATTR_METHOD_NO_DICT: { - *effect = 1; - return 0; - } - case LOAD_ATTR_METHOD_WITH_VALUES: { - *effect = 1; - return 0; - } - case LOAD_ATTR_MODULE: { - *effect = Py_MAX(0, (oparg & 1)); - return 0; - } - case LOAD_ATTR_NONDESCRIPTOR_NO_DICT: { - *effect = 0; - return 0; - } - case LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: { - *effect = 0; - return 0; - } - case LOAD_ATTR_PROPERTY: { - *effect = 0; - return 0; - } - case LOAD_ATTR_SLOT: { - *effect = Py_MAX(0, (oparg & 1)); - return 0; - } - case LOAD_ATTR_WITH_HINT: { - *effect = Py_MAX(0, (oparg & 1)); - return 0; - } - case LOAD_BUILD_CLASS: { - *effect = 1; - return 0; - } - case LOAD_CLOSURE: { - *effect = 1; - return 0; - } - case LOAD_COMMON_CONSTANT: { - *effect = 1; - return 0; - } - case LOAD_CONST: { - *effect = 1; - return 0; - } - case LOAD_CONST_IMMORTAL: { - *effect = 1; - return 0; - } - case LOAD_CONST_MORTAL: { - *effect = 1; - return 0; - } - case LOAD_DEREF: { - *effect = 1; - return 0; - } - case LOAD_FAST: { - *effect = 1; - return 0; - } - case LOAD_FAST_AND_CLEAR: { - *effect = 1; - return 0; - } - case LOAD_FAST_CHECK: { - *effect = 1; - return 0; - } - case LOAD_FAST_LOAD_FAST: { - *effect = 2; - return 0; - } - case LOAD_FROM_DICT_OR_DEREF: { - *effect = 0; - return 0; - } - case LOAD_FROM_DICT_OR_GLOBALS: { - *effect = 0; - return 0; - } - case LOAD_GLOBAL: { - *effect = Py_MAX(1, 1 + (oparg & 1)); - return 0; - } - case LOAD_GLOBAL_BUILTIN: { - *effect = Py_MAX(1, 1 + (oparg & 1)); - return 0; - } - case LOAD_GLOBAL_MODULE: { - *effect = Py_MAX(1, 1 + (oparg & 1)); - return 0; - } - case LOAD_LOCALS: { - *effect = 1; - return 0; - } - case LOAD_NAME: { - *effect = 1; - return 0; - } - case LOAD_SMALL_INT: { - *effect = 1; - return 0; - } - case LOAD_SPECIAL: { - *effect = 1; - return 0; - } - case LOAD_SUPER_ATTR: { - *effect = Py_MAX(0, -2 + (oparg & 1)); - return 0; - } - case LOAD_SUPER_ATTR_ATTR: { - *effect = -2; - return 0; - } - case LOAD_SUPER_ATTR_METHOD: { - *effect = -1; - return 0; - } - case MAKE_CELL: { - *effect = 0; - return 0; - } - case MAKE_FUNCTION: { - *effect = 0; - return 0; - } - case MAP_ADD: { - *effect = -2; - return 0; - } - case MATCH_CLASS: { - *effect = -2; - return 0; - } - case MATCH_KEYS: { - *effect = 1; - return 0; - } - case MATCH_MAPPING: { - *effect = 1; - return 0; - } - case MATCH_SEQUENCE: { - *effect = 1; - return 0; - } - case NOP: { - *effect = 0; - return 0; - } - case NOT_TAKEN: { - *effect = 0; - return 0; - } - case POP_BLOCK: { - *effect = 0; - return 0; - } - case POP_EXCEPT: { - *effect = -1; - return 0; - } - case POP_ITER: { - *effect = -1; - return 0; - } - case POP_JUMP_IF_FALSE: { - *effect = -1; - return 0; - } - case POP_JUMP_IF_NONE: { - *effect = 0; - return 0; - } - case POP_JUMP_IF_NOT_NONE: { - *effect = 0; - return 0; - } - case POP_JUMP_IF_TRUE: { - *effect = -1; - return 0; - } - case POP_TOP: { - *effect = -1; - return 0; - } - case PUSH_EXC_INFO: { - *effect = 1; - return 0; - } - case PUSH_NULL: { - *effect = 1; - return 0; - } - case RAISE_VARARGS: { - *effect = -oparg; - return 0; - } - case RERAISE: { - *effect = -1; - return 0; - } - case RESERVED: { - *effect = 0; - return 0; - } - case RESUME: { - *effect = 0; - return 0; - } - case RESUME_CHECK: { - *effect = 0; - return 0; - } - case RETURN_GENERATOR: { - *effect = 1; - return 0; - } - case RETURN_VALUE: { - *effect = 0; - return 0; - } - case SEND: { - *effect = 0; - return 0; - } - case SEND_GEN: { - *effect = 0; - return 0; - } - case SETUP_ANNOTATIONS: { - *effect = 0; - return 0; - } - case SETUP_CLEANUP: { - *effect = 2; - return 0; - } - case SETUP_FINALLY: { - *effect = 1; - return 0; - } - case SETUP_WITH: { - *effect = 1; - return 0; - } - case SET_ADD: { - *effect = -1; - return 0; - } - case SET_FUNCTION_ATTRIBUTE: { - *effect = -1; - return 0; - } - case SET_UPDATE: { - *effect = -1; - return 0; - } - case STORE_ATTR: { - *effect = 0; - return 0; - } - case STORE_ATTR_INSTANCE_VALUE: { - *effect = 0; - return 0; - } - case STORE_ATTR_SLOT: { - *effect = 0; - return 0; - } - case STORE_ATTR_WITH_HINT: { - *effect = 0; - return 0; - } - case STORE_DEREF: { - *effect = -1; - return 0; - } - case STORE_FAST: { - *effect = -1; - return 0; - } - case STORE_FAST_LOAD_FAST: { - *effect = 0; - return 0; - } - case STORE_FAST_MAYBE_NULL: { - *effect = -1; - return 0; - } - case STORE_FAST_STORE_FAST: { - *effect = -2; - return 0; - } - case STORE_GLOBAL: { - *effect = -1; - return 0; - } - case STORE_NAME: { - *effect = -1; - return 0; - } - case STORE_SLICE: { - *effect = 0; - return 0; - } - case STORE_SUBSCR: { - *effect = 0; - return 0; - } - case STORE_SUBSCR_DICT: { - *effect = -3; - return 0; - } - case STORE_SUBSCR_LIST_INT: { - *effect = -3; - return 0; - } - case SWAP: { - *effect = 0; - return 0; - } - case TO_BOOL: { - *effect = 0; - return 0; - } - case TO_BOOL_ALWAYS_TRUE: { - *effect = 0; - return 0; - } - case TO_BOOL_BOOL: { - *effect = 0; - return 0; - } - case TO_BOOL_INT: { - *effect = 0; - return 0; - } - case TO_BOOL_LIST: { - *effect = 0; - return 0; - } - case TO_BOOL_NONE: { - *effect = 0; - return 0; - } - case TO_BOOL_STR: { - *effect = 0; - return 0; - } - case UNARY_INVERT: { - *effect = 0; - return 0; - } - case UNARY_NEGATIVE: { - *effect = 0; - return 0; - } - case UNARY_NOT: { - *effect = 0; - return 0; - } - case UNPACK_EX: { - *effect = (oparg & 0xFF) + (oparg >> 8); - return 0; - } - case UNPACK_SEQUENCE: { - *effect = Py_MAX(1, -1 + oparg); - return 0; - } - case UNPACK_SEQUENCE_LIST: { - *effect = -1 + oparg; - return 0; - } - case UNPACK_SEQUENCE_TUPLE: { - *effect = -1 + oparg; - return 0; - } - case UNPACK_SEQUENCE_TWO_TUPLE: { - *effect = 1; - return 0; - } - case WITH_EXCEPT_START: { - *effect = 1; - return 0; - } - case YIELD_VALUE: { - *effect = 0; - return 0; - } - default: - return -1; - } -} - -#endif - enum InstructionFormat { INSTR_FMT_IB = 1, INSTR_FMT_IBC = 2, diff --git a/Python/flowgraph.c b/Python/flowgraph.c index cf3e74005ce1f8..565e05d6de7b3d 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -787,9 +787,6 @@ get_stack_effects(int opcode, int oparg, int jump, stack_effects *effects) effects->max = 0; return 0; } - if (_PyOpcode_max_stack_effect(opcode, oparg, &effects->max) < 0) { - return -1; - } effects->net = pushed - popped; assert(effects->max >= effects->net); return 0; diff --git a/Tools/cases_generator/opcode_metadata_generator.py b/Tools/cases_generator/opcode_metadata_generator.py index bfee3c8aa301bb..e29f6672614af7 100644 --- a/Tools/cases_generator/opcode_metadata_generator.py +++ b/Tools/cases_generator/opcode_metadata_generator.py @@ -112,101 +112,6 @@ def add(inst: Instruction | PseudoInstruction) -> None: emit_stack_effect_function(out, "popped", sorted(popped_data)) emit_stack_effect_function(out, "pushed", sorted(pushed_data)) - generate_max_stack_effect_function(analysis, out) - - -def emit_max_stack_effect_function( - out: CWriter, effects: list[tuple[str, list[str]]] -) -> None: - out.emit("extern int _PyOpcode_max_stack_effect(int opcode, int oparg, int *effect);\n") - out.emit("#ifdef NEED_OPCODE_METADATA\n") - out.emit(f"int _PyOpcode_max_stack_effect(int opcode, int oparg, int *effect) {{\n") - out.emit("switch(opcode) {\n") - for name, exprs in effects: - out.emit(f"case {name}: {{\n") - if len(exprs) == 1: - out.emit(f"*effect = {exprs[0]};\n") - elif len(exprs) == 2: - out.emit(f"*effect = Py_MAX({exprs[0]}, {exprs[1]});\n") - else: - assert len(exprs) > 2 - out.emit(f"int max_eff = Py_MAX({exprs[0]}, {exprs[1]});\n") - for expr in exprs[2:]: - out.emit(f"max_eff = Py_MAX(max_eff, {expr});\n") - out.emit(f"*effect = max_eff;\n") - out.emit(f"return 0;\n") - out.emit("}\n") - out.emit("default:\n") - out.emit(" return -1;\n") - out.emit("}\n") - out.emit("}\n\n") - out.emit("#endif\n\n") - - -@dataclass -class MaxStackEffectSet: - int_effect: int | None - cond_effects: set[str] - - def __init__(self) -> None: - self.int_effect = None - self.cond_effects = set() - - def add(self, stack: Stack) -> None: - top_off = stack.top_offset - top_off_int = top_off.as_int() - if top_off_int is not None: - if self.int_effect is None or top_off_int > self.int_effect: - self.int_effect = top_off_int - else: - self.cond_effects.add(top_off.to_c()) - - def update(self, other: "MaxStackEffectSet") -> None: - if self.int_effect is None: - if other.int_effect is not None: - self.int_effect = other.int_effect - elif other.int_effect is not None: - self.int_effect = max(self.int_effect, other.int_effect) - self.cond_effects.update(other.cond_effects) - - -def generate_max_stack_effect_function(analysis: Analysis, out: CWriter) -> None: - """Generate a function that returns the maximum stack effect of an - instruction while it is executing. - - Specialized instructions that are composed of uops may have a greater stack - effect during instruction execution than the net stack effect of the - instruction if the uops pass values on the stack. - """ - effects: dict[str, MaxStackEffectSet] = {} - - def add(inst: Instruction | PseudoInstruction) -> None: - inst_effect = MaxStackEffectSet() - for stack in get_stack_effects(inst): - inst_effect.add(stack) - effects[inst.name] = inst_effect - - # Collect unique stack effects for each instruction - for inst in analysis.instructions.values(): - add(inst) - for pseudo in analysis.pseudos.values(): - add(pseudo) - - # Merge the effects of all specializations in a family into the generic - # instruction - for family in analysis.families.values(): - for inst in family.members: - effects[family.name].update(effects[inst.name]) - - data: list[tuple[str, list[str]]] = [] - for name, effs in sorted(effects.items(), key=lambda kv: kv[0]): - exprs = [] - if effs.int_effect is not None: - exprs.append(str(effs.int_effect)) - exprs.extend(sorted(effs.cond_effects)) - data.append((name, exprs)) - emit_max_stack_effect_function(out, data) - def generate_is_pseudo(analysis: Analysis, out: CWriter) -> None: """Write the IS_PSEUDO_INSTR macro""" From 54d8bfbec896756b2c1d2d305bf1a277d52d17ad Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 20 Mar 2025 09:50:56 +0000 Subject: [PATCH 2/4] Remove more unused code --- Tools/cases_generator/opcode_metadata_generator.py | 2 +- Tools/cases_generator/stack.py | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/Tools/cases_generator/opcode_metadata_generator.py b/Tools/cases_generator/opcode_metadata_generator.py index e29f6672614af7..9cfa30bd3b2afe 100644 --- a/Tools/cases_generator/opcode_metadata_generator.py +++ b/Tools/cases_generator/opcode_metadata_generator.py @@ -21,7 +21,7 @@ from cwriter import CWriter from dataclasses import dataclass from typing import TextIO -from stack import Stack, get_stack_effect, get_stack_effects +from stack import get_stack_effect # Constants used instead of size for macro expansions. # Note: 1, 2, 4 must match actual cache entry sizes. diff --git a/Tools/cases_generator/stack.py b/Tools/cases_generator/stack.py index eb7d1967eb75c3..51c4c810e20714 100644 --- a/Tools/cases_generator/stack.py +++ b/Tools/cases_generator/stack.py @@ -416,16 +416,6 @@ def get_stack_effect(inst: Instruction | PseudoInstruction) -> Stack: return stack -def get_stack_effects(inst: Instruction | PseudoInstruction) -> list[Stack]: - """Returns a list of stack effects after each uop""" - result = [] - stack = Stack() - for s in stacks(inst): - apply_stack_effect(stack, s) - result.append(stack.copy()) - return result - - @dataclass class Storage: From e70bfd6d5c178ada6aa0038d7d137b3e1f20b15d Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 20 Mar 2025 10:17:04 +0000 Subject: [PATCH 3/4] Remove all references to max stack --- Lib/test/test_generated_cases.py | 171 ------------------------------- Python/flowgraph.c | 11 +- 2 files changed, 2 insertions(+), 180 deletions(-) diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index 32d14548159cce..39ad07ff79be31 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -77,171 +77,6 @@ def test_effect_sizes(self): self.assertEqual(stack.top_offset.to_c(), "1 - oparg - oparg*2 + oparg*4") -class TestGenerateMaxStackEffect(unittest.TestCase): - def check(self, input, output): - analysis = analyze_forest(parse_src(input)) - buf = StringIO() - writer = CWriter(buf, 0, False) - opcode_metadata_generator.generate_max_stack_effect_function(analysis, writer) - buf.seek(0) - generated = buf.read() - matches = re.search(r"(case OP: {[^}]+})", generated) - if matches is None: - self.fail(f"Couldn't find case statement for OP in:\n {generated}") - self.assertEqual(output.strip(), matches.group(1)) - - def test_push_one(self): - input = """ - inst(OP, (a -- b, c)) { - SPAM(); - } - """ - output = """ - case OP: { - *effect = 1; - return 0; - } - """ - self.check(input, output) - - def test_cond_push(self): - input = """ - inst(OP, (a -- b, c if (oparg))) { - SPAM(); - } - """ - output = """ - case OP: { - *effect = ((oparg) ? 1 : 0); - return 0; - } - """ - self.check(input, output) - - def test_ops_pass_two(self): - input = """ - op(A, (-- val1)) { - val1 = SPAM(); - } - op(B, (-- val2)) { - val2 = SPAM(); - } - op(C, (val1, val2 --)) { - } - macro(OP) = A + B + C; - """ - output = """ - case OP: { - *effect = 2; - return 0; - } - """ - self.check(input, output) - - def test_ops_pass_two_cond_push(self): - input = """ - op(A, (-- val1, val2)) { - val1 = 0; - val2 = 1; - } - op(B, (val1, val2 -- val1, val2, val3 if (oparg))) { - val3 = SPAM(); - } - macro(OP) = A + B; - """ - output = """ - case OP: { - *effect = Py_MAX(2, 2 + ((oparg) ? 1 : 0)); - return 0; - } - """ - self.check(input, output) - - def test_pop_push_array(self): - input = """ - inst(OP, (values[oparg] -- values[oparg], above)) { - SPAM(values, oparg); - above = 0; - } - """ - output = """ - case OP: { - *effect = 1; - return 0; - } - """ - self.check(input, output) - - def test_family(self): - input = """ - op(A, (-- val1, val2)) { - val1 = 0; - val2 = 1; - } - op(B, (val1, val2 -- val3)) { - val3 = 2; - } - macro(OP1) = A + B; - - inst(OP, (-- val)) { - val = 0; - } - - family(OP, 0) = { OP1 }; - """ - output = """ - case OP: { - *effect = 2; - return 0; - } - """ - self.check(input, output) - - def test_family_intermediate_array(self): - input = """ - op(A, (-- values[oparg])) { - val1 = 0; - val2 = 1; - } - op(B, (values[oparg] -- val3)) { - val3 = 2; - } - macro(OP1) = A + B; - - inst(OP, (-- val)) { - val = 0; - } - - family(OP, 0) = { OP1 }; - """ - output = """ - case OP: { - *effect = Py_MAX(1, oparg); - return 0; - } - """ - self.check(input, output) - - def test_negative_effect(self): - input = """ - op(A, (val1 -- )) { - } - op(B, (val2 --)) { - } - op(C, (val3 --)) { - } - - macro(OP) = A + B + C; - """ - output = """ - case OP: { - *effect = -1; - return 0; - } - """ - self.check(input, output) - - class TestGeneratedCases(unittest.TestCase): def setUp(self) -> None: super().setUp() @@ -287,12 +122,6 @@ def run_cases_test(self, input: str, expected: str): _, labels_with_postlude = labels_with_prelude_and_postlude.split(tier1_generator.LABEL_START_MARKER) labels, _ = labels_with_postlude.split(tier1_generator.LABEL_END_MARKER) actual = instructions.strip() + "\n\n " + labels.strip() - # if actual.strip() != expected.strip(): - # print("Actual:") - # print(actual) - # print("Expected:") - # print(expected) - # print("End") self.assertEqual(actual.strip(), expected.strip()) diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 565e05d6de7b3d..4f101a602c555e 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -760,11 +760,6 @@ make_cfg_traversal_stack(basicblock *entryblock) { typedef struct { /* The stack effect of the instruction. */ int net; - - /* The maximum stack usage of the instruction. Some instructions may - * temporarily push extra values to the stack while they are executing. - */ - int max; } stack_effects; Py_LOCAL(int) @@ -784,11 +779,9 @@ get_stack_effects(int opcode, int oparg, int jump, stack_effects *effects) } if (IS_BLOCK_PUSH_OPCODE(opcode) && !jump) { effects->net = 0; - effects->max = 0; return 0; } effects->net = pushed - popped; - assert(effects->max >= effects->net); return 0; } @@ -849,7 +842,7 @@ calculate_stackdepth(cfg_builder *g) "Invalid CFG, stack underflow"); goto error; } - maxdepth = Py_MAX(maxdepth, depth + effects.max); + maxdepth = Py_MAX(maxdepth, depth); if (HAS_TARGET(instr->i_opcode) && instr->i_opcode != END_ASYNC_FOR) { if (get_stack_effects(instr->i_opcode, instr->i_oparg, 1, &effects) < 0) { PyErr_Format(PyExc_SystemError, @@ -859,7 +852,7 @@ calculate_stackdepth(cfg_builder *g) } int target_depth = depth + effects.net; assert(target_depth >= 0); /* invalid code or bug in stackdepth() */ - maxdepth = Py_MAX(maxdepth, depth + effects.max); + maxdepth = Py_MAX(maxdepth, depth); if (stackdepth_push(&sp, instr->i_target, target_depth) < 0) { goto error; } From 5ea79f66353b44efda483d0ecc2a9a818f9a22c1 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 20 Mar 2025 10:53:04 +0000 Subject: [PATCH 4/4] Update test_frozenmain --- Programs/test_frozenmain.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 281cf1c1bf9b27..76a335086c9b11 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -1,6 +1,6 @@ // Auto-generated by Programs/freeze_test_frozenmain.py unsigned char M_test_frozenmain[] = { - 227,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0, + 227,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, 0,0,0,0,0,243,184,0,0,0,128,0,90,0,80,1, 71,0,112,0,90,0,80,1,71,1,112,1,89,2,32,0, 80,2,50,1,0,0,0,0,0,0,30,0,89,2,32,0,