#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,
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()
_, 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())
// 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,
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)
}
if (IS_BLOCK_PUSH_OPCODE(opcode) && !jump) {
effects->net = 0;
- 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;
}
"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,
}
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 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.
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"""
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: