diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index fa4cbd9ed31c01..482f217248e39a 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -27,57 +27,59 @@ #define EXIT_TRACE 300 #define SAVE_IP 301 -#define _GUARD_BOTH_INT 302 -#define _BINARY_OP_MULTIPLY_INT 303 -#define _BINARY_OP_ADD_INT 304 -#define _BINARY_OP_SUBTRACT_INT 305 -#define _GUARD_BOTH_FLOAT 306 -#define _BINARY_OP_MULTIPLY_FLOAT 307 -#define _BINARY_OP_ADD_FLOAT 308 -#define _BINARY_OP_SUBTRACT_FLOAT 309 -#define _GUARD_BOTH_UNICODE 310 -#define _BINARY_OP_ADD_UNICODE 311 -#define _BINARY_OP_INPLACE_ADD_UNICODE 312 -#define _POP_FRAME 313 -#define _LOAD_LOCALS 314 -#define _LOAD_FROM_DICT_OR_GLOBALS 315 -#define _GUARD_GLOBALS_VERSION 316 -#define _GUARD_BUILTINS_VERSION 317 -#define _LOAD_GLOBAL_MODULE 318 -#define _LOAD_GLOBAL_BUILTINS 319 -#define _GUARD_TYPE_VERSION 320 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES 321 -#define _LOAD_ATTR_INSTANCE_VALUE 322 -#define IS_NONE 323 -#define _ITER_CHECK_LIST 324 -#define _ITER_JUMP_LIST 325 -#define _IS_ITER_EXHAUSTED_LIST 326 -#define _ITER_NEXT_LIST 327 -#define _ITER_CHECK_TUPLE 328 -#define _ITER_JUMP_TUPLE 329 -#define _IS_ITER_EXHAUSTED_TUPLE 330 -#define _ITER_NEXT_TUPLE 331 -#define _ITER_CHECK_RANGE 332 -#define _ITER_JUMP_RANGE 333 -#define _IS_ITER_EXHAUSTED_RANGE 334 -#define _ITER_NEXT_RANGE 335 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 336 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 337 -#define _CHECK_PEP_523 338 -#define _CHECK_FUNCTION_EXACT_ARGS 339 -#define _CHECK_STACK_SPACE 340 -#define _INIT_CALL_PY_EXACT_ARGS 341 -#define _PUSH_FRAME 342 -#define _POP_JUMP_IF_FALSE 343 -#define _POP_JUMP_IF_TRUE 344 -#define JUMP_TO_TOP 345 -#define SAVE_CURRENT_IP 346 +#define _SAVE_CURRENT_IP 302 +#define _GUARD_BOTH_INT 303 +#define _BINARY_OP_MULTIPLY_INT 304 +#define _BINARY_OP_ADD_INT 305 +#define _BINARY_OP_SUBTRACT_INT 306 +#define _GUARD_BOTH_FLOAT 307 +#define _BINARY_OP_MULTIPLY_FLOAT 308 +#define _BINARY_OP_ADD_FLOAT 309 +#define _BINARY_OP_SUBTRACT_FLOAT 310 +#define _GUARD_BOTH_UNICODE 311 +#define _BINARY_OP_ADD_UNICODE 312 +#define _BINARY_OP_INPLACE_ADD_UNICODE 313 +#define _POP_FRAME 314 +#define _LOAD_LOCALS 315 +#define _LOAD_FROM_DICT_OR_GLOBALS 316 +#define _GUARD_GLOBALS_VERSION 317 +#define _GUARD_BUILTINS_VERSION 318 +#define _LOAD_GLOBAL_MODULE 319 +#define _LOAD_GLOBAL_BUILTINS 320 +#define _GUARD_TYPE_VERSION 321 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES 322 +#define _LOAD_ATTR_INSTANCE_VALUE 323 +#define IS_NONE 324 +#define _ITER_CHECK_LIST 325 +#define _ITER_JUMP_LIST 326 +#define _IS_ITER_EXHAUSTED_LIST 327 +#define _ITER_NEXT_LIST 328 +#define _ITER_CHECK_TUPLE 329 +#define _ITER_JUMP_TUPLE 330 +#define _IS_ITER_EXHAUSTED_TUPLE 331 +#define _ITER_NEXT_TUPLE 332 +#define _ITER_CHECK_RANGE 333 +#define _ITER_JUMP_RANGE 334 +#define _IS_ITER_EXHAUSTED_RANGE 335 +#define _ITER_NEXT_RANGE 336 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 337 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 338 +#define _CHECK_PEP_523 339 +#define _CHECK_FUNCTION_EXACT_ARGS 340 +#define _CHECK_STACK_SPACE 341 +#define _INIT_CALL_PY_EXACT_ARGS 342 +#define _PUSH_FRAME 343 +#define _SIDE_EXIT_IF_FALSE 344 +#define _SIDE_EXIT_IF_TRUE 345 +#define JUMP_TO_TOP 346 #define INSERT 347 extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); #ifdef NEED_OPCODE_METADATA int _PyOpcode_num_popped(int opcode, int oparg, bool jump) { switch(opcode) { + case _SAVE_CURRENT_IP: + return 0; case NOP: return 0; case RESUME: @@ -586,16 +588,14 @@ int _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 0; case RESERVED: return 0; - case _POP_JUMP_IF_FALSE: + case _SIDE_EXIT_IF_FALSE: return 1; - case _POP_JUMP_IF_TRUE: + case _SIDE_EXIT_IF_TRUE: return 1; case JUMP_TO_TOP: return 0; case SAVE_IP: return 0; - case SAVE_CURRENT_IP: - return 0; case EXIT_TRACE: return 0; case INSERT: @@ -610,6 +610,8 @@ extern int _PyOpcode_num_pushed(int opcode, int oparg, bool jump); #ifdef NEED_OPCODE_METADATA int _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { switch(opcode) { + case _SAVE_CURRENT_IP: + return 0; case NOP: return 0; case RESUME: @@ -1118,16 +1120,14 @@ int _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case RESERVED: return 0; - case _POP_JUMP_IF_FALSE: + case _SIDE_EXIT_IF_FALSE: return 0; - case _POP_JUMP_IF_TRUE: + case _SIDE_EXIT_IF_TRUE: return 0; case JUMP_TO_TOP: return 0; case SAVE_IP: return 0; - case SAVE_CURRENT_IP: - return 0; case EXIT_TRACE: return 0; case INSERT: @@ -1205,6 +1205,7 @@ struct opcode_macro_expansion { extern const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE]; #ifdef NEED_OPCODE_METADATA const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { + [_SAVE_CURRENT_IP] = { true, INSTR_FMT_IX, 0 }, [NOP] = { true, INSTR_FMT_IX, 0 }, [RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG }, [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG }, @@ -1463,11 +1464,10 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [EXTENDED_ARG] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [CACHE] = { true, INSTR_FMT_IX, 0 }, [RESERVED] = { true, INSTR_FMT_IX, 0 }, - [_POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [_SIDE_EXIT_IF_FALSE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [_SIDE_EXIT_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [JUMP_TO_TOP] = { true, INSTR_FMT_IX, HAS_EVAL_BREAK_FLAG }, [SAVE_IP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [SAVE_CURRENT_IP] = { true, INSTR_FMT_IX, 0 }, [EXIT_TRACE] = { true, INSTR_FMT_IX, 0 }, [INSERT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, }; @@ -1522,8 +1522,8 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN [DELETE_SUBSCR] = { .nuops = 1, .uops = { { DELETE_SUBSCR, 0, 0 } } }, [CALL_INTRINSIC_1] = { .nuops = 1, .uops = { { CALL_INTRINSIC_1, 0, 0 } } }, [CALL_INTRINSIC_2] = { .nuops = 1, .uops = { { CALL_INTRINSIC_2, 0, 0 } } }, - [RETURN_VALUE] = { .nuops = 3, .uops = { { SAVE_IP, 7, 0 }, { SAVE_CURRENT_IP, 0, 0 }, { _POP_FRAME, 0, 0 } } }, - [RETURN_CONST] = { .nuops = 4, .uops = { { LOAD_CONST, 0, 0 }, { SAVE_IP, 7, 0 }, { SAVE_CURRENT_IP, 0, 0 }, { _POP_FRAME, 0, 0 } } }, + [RETURN_VALUE] = { .nuops = 1, .uops = { { _POP_FRAME, 0, 0 } } }, + [RETURN_CONST] = { .nuops = 2, .uops = { { LOAD_CONST, 0, 0 }, { _POP_FRAME, 0, 0 } } }, [GET_AITER] = { .nuops = 1, .uops = { { GET_AITER, 0, 0 } } }, [GET_ANEXT] = { .nuops = 1, .uops = { { GET_ANEXT, 0, 0 } } }, [GET_AWAITABLE] = { .nuops = 1, .uops = { { GET_AWAITABLE, 0, 0 } } }, @@ -1586,8 +1586,8 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN [GET_YIELD_FROM_ITER] = { .nuops = 1, .uops = { { GET_YIELD_FROM_ITER, 0, 0 } } }, [WITH_EXCEPT_START] = { .nuops = 1, .uops = { { WITH_EXCEPT_START, 0, 0 } } }, [PUSH_EXC_INFO] = { .nuops = 1, .uops = { { PUSH_EXC_INFO, 0, 0 } } }, - [CALL_BOUND_METHOD_EXACT_ARGS] = { .nuops = 9, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _INIT_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { SAVE_IP, 7, 3 }, { SAVE_CURRENT_IP, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, - [CALL_PY_EXACT_ARGS] = { .nuops = 7, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { SAVE_IP, 7, 3 }, { SAVE_CURRENT_IP, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, + [CALL_BOUND_METHOD_EXACT_ARGS] = { .nuops = 8, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _INIT_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SAVE_CURRENT_IP, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, + [CALL_PY_EXACT_ARGS] = { .nuops = 6, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SAVE_CURRENT_IP, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, [CALL_NO_KW_TYPE_1] = { .nuops = 1, .uops = { { CALL_NO_KW_TYPE_1, 0, 0 } } }, [CALL_NO_KW_STR_1] = { .nuops = 1, .uops = { { CALL_NO_KW_STR_1, 0, 0 } } }, [CALL_NO_KW_TUPLE_1] = { .nuops = 1, .uops = { { CALL_NO_KW_TUPLE_1, 0, 0 } } }, @@ -1616,6 +1616,7 @@ extern const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE]; const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = { [EXIT_TRACE] = "EXIT_TRACE", [SAVE_IP] = "SAVE_IP", + [_SAVE_CURRENT_IP] = "_SAVE_CURRENT_IP", [_GUARD_BOTH_INT] = "_GUARD_BOTH_INT", [_BINARY_OP_MULTIPLY_INT] = "_BINARY_OP_MULTIPLY_INT", [_BINARY_OP_ADD_INT] = "_BINARY_OP_ADD_INT", @@ -1657,10 +1658,9 @@ const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = { [_CHECK_STACK_SPACE] = "_CHECK_STACK_SPACE", [_INIT_CALL_PY_EXACT_ARGS] = "_INIT_CALL_PY_EXACT_ARGS", [_PUSH_FRAME] = "_PUSH_FRAME", - [_POP_JUMP_IF_FALSE] = "_POP_JUMP_IF_FALSE", - [_POP_JUMP_IF_TRUE] = "_POP_JUMP_IF_TRUE", + [_SIDE_EXIT_IF_FALSE] = "_SIDE_EXIT_IF_FALSE", + [_SIDE_EXIT_IF_TRUE] = "_SIDE_EXIT_IF_TRUE", [JUMP_TO_TOP] = "JUMP_TO_TOP", - [SAVE_CURRENT_IP] = "SAVE_CURRENT_IP", [INSERT] = "INSERT", }; #endif // NEED_OPCODE_METADATA diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 004ce397696556..3e7b37f8c9d9b1 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2475,7 +2475,7 @@ def testfunc(n): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) uops = {opname for opname, _, _ in ex} - self.assertIn("_POP_JUMP_IF_FALSE", uops) + self.assertIn("_SIDE_EXIT_IF_FALSE", uops) def test_pop_jump_if_none(self): def testfunc(a): @@ -2490,7 +2490,7 @@ def testfunc(a): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) uops = {opname for opname, _, _ in ex} - self.assertIn("_POP_JUMP_IF_TRUE", uops) + self.assertIn("_SIDE_EXIT_IF_TRUE", uops) def test_pop_jump_if_not_none(self): def testfunc(a): @@ -2505,7 +2505,7 @@ def testfunc(a): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) uops = {opname for opname, _, _ in ex} - self.assertIn("_POP_JUMP_IF_FALSE", uops) + self.assertIn("_SIDE_EXIT_IF_FALSE", uops) def test_pop_jump_if_true(self): def testfunc(n): @@ -2520,7 +2520,7 @@ def testfunc(n): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) uops = {opname for opname, _, _ in ex} - self.assertIn("_POP_JUMP_IF_TRUE", uops) + self.assertIn("_SIDE_EXIT_IF_TRUE", uops) def test_jump_backward(self): def testfunc(n): diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index 07e8a711575c5b..71cc6279723937 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -3,6 +3,10 @@ // Python/bytecodes.c // Do not edit! + case _SAVE_CURRENT_IP: { + break; + } + case NOP: { break; } @@ -776,12 +780,12 @@ break; } - case _POP_JUMP_IF_FALSE: { + case _SIDE_EXIT_IF_FALSE: { STACK_SHRINK(1); break; } - case _POP_JUMP_IF_TRUE: { + case _SIDE_EXIT_IF_TRUE: { STACK_SHRINK(1); break; } @@ -794,10 +798,6 @@ break; } - case SAVE_CURRENT_IP: { - break; - } - case EXIT_TRACE: { break; } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index fae1da31875d66..bfab2e80f1b6ae 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -129,6 +129,11 @@ dummy_func( switch (opcode) { // BEGIN BYTECODES // + + op(_SAVE_CURRENT_IP, (--)) { + frame->prev_instr = next_instr - 1; + } + inst(NOP, (--)) { } @@ -790,8 +795,6 @@ dummy_func( } macro(RETURN_VALUE) = - SAVE_IP + // Tier 2 only; special-cased oparg - SAVE_CURRENT_IP + // Sets frame->prev_instr _POP_FRAME; inst(INSTRUMENTED_RETURN_VALUE, (retval --)) { @@ -815,8 +818,6 @@ dummy_func( macro(RETURN_CONST) = LOAD_CONST + - SAVE_IP + // Tier 2 only; special-cased oparg - SAVE_CURRENT_IP + // Sets frame->prev_instr _POP_FRAME; inst(INSTRUMENTED_RETURN_CONST, (--)) { @@ -3022,8 +3023,7 @@ dummy_func( _CHECK_FUNCTION_EXACT_ARGS + _CHECK_STACK_SPACE + _INIT_CALL_PY_EXACT_ARGS + - SAVE_IP + // Tier 2 only; special-cased oparg - SAVE_CURRENT_IP + // Sets frame->prev_instr + _SAVE_CURRENT_IP + // Sets frame->prev_instr _PUSH_FRAME; macro(CALL_PY_EXACT_ARGS) = @@ -3032,8 +3032,7 @@ dummy_func( _CHECK_FUNCTION_EXACT_ARGS + _CHECK_STACK_SPACE + _INIT_CALL_PY_EXACT_ARGS + - SAVE_IP + // Tier 2 only; special-cased oparg - SAVE_CURRENT_IP + // Sets frame->prev_instr + _SAVE_CURRENT_IP + // Sets frame->prev_instr _PUSH_FRAME; inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, callable, self_or_null, args[oparg] -- unused)) { @@ -3776,13 +3775,13 @@ dummy_func( ///////// Tier-2 only opcodes ///////// - op(_POP_JUMP_IF_FALSE, (flag -- )) { + op(_SIDE_EXIT_IF_FALSE, (flag -- )) { if (Py_IsFalse(flag)) { pc = oparg; } } - op(_POP_JUMP_IF_TRUE, (flag -- )) { + op(_SIDE_EXIT_IF_TRUE, (flag -- )) { if (Py_IsTrue(flag)) { pc = oparg; } @@ -3797,16 +3796,6 @@ dummy_func( frame->prev_instr = ip_offset + oparg; } - op(SAVE_CURRENT_IP, (--)) { - #if TIER_ONE - frame->prev_instr = next_instr - 1; - #endif - #if TIER_TWO - // Relies on a preceding SAVE_IP - frame->prev_instr--; - #endif - } - op(EXIT_TRACE, (--)) { frame->prev_instr--; // Back up to just before destination _PyFrame_SetStackPointer(frame, stack_pointer); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 0d5606f5a44efe..47429ddff1fb66 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3,6 +3,17 @@ // Python/bytecodes.c // Do not edit! + case _SAVE_CURRENT_IP: { + #if TIER_ONE + frame->prev_instr = next_instr - 1; + #endif + #if TIER_TWO + /* Should be eliminated in tier 2 */ + assert(0); + #endif + break; + } + case NOP: { break; } @@ -2838,7 +2849,7 @@ break; } - case _POP_JUMP_IF_FALSE: { + case _SIDE_EXIT_IF_FALSE: { PyObject *flag; flag = stack_pointer[-1]; if (Py_IsFalse(flag)) { @@ -2848,7 +2859,7 @@ break; } - case _POP_JUMP_IF_TRUE: { + case _SIDE_EXIT_IF_TRUE: { PyObject *flag; flag = stack_pointer[-1]; if (Py_IsTrue(flag)) { @@ -2869,17 +2880,6 @@ break; } - case SAVE_CURRENT_IP: { - #if TIER_ONE - frame->prev_instr = next_instr - 1; - #endif - #if TIER_TWO - // Relies on a preceding SAVE_IP - frame->prev_instr--; - #endif - break; - } - case EXIT_TRACE: { frame->prev_instr--; // Back up to just before destination _PyFrame_SetStackPointer(frame, stack_pointer); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 34cea84245f591..d818ce7f99b58f 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -975,41 +975,28 @@ TARGET(RETURN_VALUE) { PyObject *retval; - // SAVE_CURRENT_IP - { - #if TIER_ONE - frame->prev_instr = next_instr - 1; - #endif - #if TIER_TWO - // Relies on a preceding SAVE_IP - frame->prev_instr--; - #endif - } - // _POP_FRAME retval = stack_pointer[-1]; STACK_SHRINK(1); - { - assert(EMPTY()); - #if TIER_ONE - assert(frame != &entry_frame); - #endif - STORE_SP(); - _Py_LeaveRecursiveCallPy(tstate); - // GH-99729: We need to unlink the frame *before* clearing it: - _PyInterpreterFrame *dying = frame; - frame = tstate->current_frame = dying->previous; - _PyEval_FrameClearAndPop(tstate, dying); - frame->prev_instr += frame->return_offset; - _PyFrame_StackPush(frame, retval); - LOAD_SP(); - LOAD_IP(); - #if LLTRACE && TIER_ONE - lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); - if (lltrace < 0) { - goto exit_unwind; - } - #endif + assert(EMPTY()); + #if TIER_ONE + assert(frame != &entry_frame); + #endif + STORE_SP(); + _Py_LeaveRecursiveCallPy(tstate); + // GH-99729: We need to unlink the frame *before* clearing it: + _PyInterpreterFrame *dying = frame; + frame = tstate->current_frame = dying->previous; + _PyEval_FrameClearAndPop(tstate, dying); + frame->prev_instr += frame->return_offset; + _PyFrame_StackPush(frame, retval); + LOAD_SP(); + LOAD_IP(); +#if LLTRACE && TIER_ONE + lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); + if (lltrace < 0) { + goto exit_unwind; } +#endif DISPATCH(); } @@ -1043,16 +1030,6 @@ value = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(value); } - // SAVE_CURRENT_IP - { - #if TIER_ONE - frame->prev_instr = next_instr - 1; - #endif - #if TIER_TWO - // Relies on a preceding SAVE_IP - frame->prev_instr--; - #endif - } // _POP_FRAME retval = value; { @@ -3860,15 +3837,15 @@ new_frame->localsplus[i] = args[i]; } } - // SAVE_CURRENT_IP + // _SAVE_CURRENT_IP next_instr += 3; { #if TIER_ONE frame->prev_instr = next_instr - 1; #endif #if TIER_TWO - // Relies on a preceding SAVE_IP - frame->prev_instr--; + /* Should be eliminated in tier 2 */ + assert(0); #endif } // _PUSH_FRAME @@ -3939,15 +3916,15 @@ new_frame->localsplus[i] = args[i]; } } - // SAVE_CURRENT_IP + // _SAVE_CURRENT_IP next_instr += 3; { #if TIER_ONE frame->prev_instr = next_instr - 1; #endif #if TIER_TWO - // Relies on a preceding SAVE_IP - frame->prev_instr--; + /* Should be eliminated in tier 2 */ + assert(0); #endif } // _PUSH_FRAME diff --git a/Python/optimizer.c b/Python/optimizer.c index 7472f52c50b766..eb65528b406f76 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -386,8 +386,8 @@ move_stubs( (stubs_end - stubs_start) * sizeof(_PyUOpInstruction)); // Patch up the jump targets for (int i = 0; i < trace_length; i++) { - if (trace[i].opcode == _POP_JUMP_IF_FALSE || - trace[i].opcode == _POP_JUMP_IF_TRUE) + if (trace[i].opcode == _SIDE_EXIT_IF_FALSE || + trace[i].opcode == _SIDE_EXIT_IF_TRUE) { int target = trace[i].oparg; if (target >= stubs_start) { @@ -503,7 +503,6 @@ translate_bytecode_to_trace( top: // Jump here after _PUSH_FRAME for (;;) { RESERVE_RAW(2, "epilogue"); // Always need space for SAVE_IP and EXIT_TRACE - ADD_TO_TRACE(SAVE_IP, INSTR_IP(instr, code), 0); uint32_t opcode = instr->op.code; uint32_t oparg = instr->op.arg; @@ -552,7 +551,7 @@ translate_bytecode_to_trace( instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]] + oparg; max_length -= 2; // Really the start of the stubs uint32_t uopcode = opcode == POP_JUMP_IF_TRUE ? - _POP_JUMP_IF_TRUE : _POP_JUMP_IF_FALSE; + _SIDE_EXIT_IF_TRUE : _SIDE_EXIT_IF_FALSE; ADD_TO_TRACE(uopcode, max_length, 0); ADD_TO_STUB(max_length, SAVE_IP, INSTR_IP(target_instr, code), 0); ADD_TO_STUB(max_length + 1, EXIT_TRACE, 0, 0); @@ -610,7 +609,7 @@ translate_bytecode_to_trace( max_length -= 3; // Really the start of the stubs ADD_TO_TRACE(check_op, 0, 0); ADD_TO_TRACE(exhausted_op, 0, 0); - ADD_TO_TRACE(_POP_JUMP_IF_TRUE, max_length, 0); + ADD_TO_TRACE(_SIDE_EXIT_IF_TRUE, max_length, 0); ADD_TO_TRACE(next_op, 0, 0); ADD_TO_STUB(max_length + 0, POP_TOP, 0, 0); @@ -679,7 +678,12 @@ translate_bytecode_to_trace( expansion->uops[i].offset); Py_FatalError("garbled expansion"); } - ADD_TO_TRACE(expansion->uops[i].uop, oparg, operand); + if (expansion->uops[i].uop == _SAVE_CURRENT_IP) { + ADD_TO_TRACE(SAVE_IP, INSTR_IP(instr, code), 0); + } + else { + ADD_TO_TRACE(expansion->uops[i].uop, oparg, operand); + } if (expansion->uops[i].uop == _POP_FRAME) { TRACE_STACK_POP(); DPRINTF(2, @@ -811,7 +815,7 @@ remove_unneeded_uops(_PyUOpInstruction *trace, int trace_length) bool need_ip = true; for (int pc = 0; pc < trace_length; pc++) { int opcode = trace[pc].opcode; - if (opcode == SAVE_CURRENT_IP) { + if (opcode == _SAVE_CURRENT_IP) { // Special case: never remove preceding SAVE_IP last_save_ip = -1; } @@ -890,7 +894,7 @@ uop_optimize( if (uop_optimize != NULL && *uop_optimize > '0') { trace_length = _Py_uop_analyze_and_optimize(code, trace, trace_length, curr_stackentries); } - trace_length = remove_unneeded_uops(trace, trace_length); + // trace_length = remove_unneeded_uops(trace, trace_length); _PyUOpExecutorObject *executor = PyObject_NewVar(_PyUOpExecutorObject, &UOpExecutor_Type, trace_length); if (executor == NULL) { return -1; diff --git a/Tools/cases_generator/analysis.py b/Tools/cases_generator/analysis.py index 7c7c9086cd72f5..f94e42d09d7f22 100644 --- a/Tools/cases_generator/analysis.py +++ b/Tools/cases_generator/analysis.py @@ -177,6 +177,27 @@ def parse_file(self, filename: str, instrs_idx: dict[str, int]) -> None: if not psr.eof(): raise psr.make_syntax_error(f"Extra stuff at the end of {filename}") + def desugar(self) -> None: + "Desuger inst" + new_ops = {} + to_remove = [] + for name, inst in self.instrs.items(): + if isinstance(inst, Instruction): + if inst.kind == "op": + continue + name = inst.name + op_name = "_" + name + inst.name = op_name + new_ops[op_name] = inst + uops = [ parsing.OpName("_SAVE_CURRENT_IP"), parsing.OpName(op_name) ] + macro = parsing.Macro(name, uops) + self.macros[name] = macro + self.everything.append(macro) + to_remove.append(name) + self.instrs.update(new_ops) + for name in to_remove: + del self.instrs[name] + def analyze(self) -> None: """Analyze the inputs. @@ -376,9 +397,9 @@ def analyze_macro(self, macro: parsing.Macro) -> MacroInstruction: return MacroInstruction(macro.name, format, flags, macro, parts, offset) def analyze_pseudo(self, pseudo: parsing.Pseudo) -> PseudoInstruction: - targets = [self.instrs[target] for target in pseudo.targets] + targets = [self.macro_instrs[target] for target in pseudo.targets] assert targets - # Make sure the targets have the same fmt + # TO DO -- Make sure the targets have the same fmt fmts = list(set([t.instr_fmt for t in targets])) assert len(fmts) == 1 ignored_flags = {"HAS_EVAL_BREAK_FLAG", "HAS_DEOPT_FLAG", "HAS_ERROR_FLAG"} @@ -406,7 +427,11 @@ def check_macro_components( match uop: case parsing.OpName(name): if name not in self.instrs: - self.error(f"Unknown instruction {name!r}", macro) + op_name = "_" + name + if name in self.macros and op_name in self.instrs: + name = op_name + else: + self.error(f"Unknown instruction {name!r}", macro) components.append(self.instrs[name]) case parsing.CacheEffect(): components.append(uop) diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 1335c0c29ebbf6..b2be2625fa271f 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -777,9 +777,7 @@ def write_instructions( case OverriddenInstructionPlaceHolder(): self.write_overridden_instr_place_holder(thing) case parsing.InstDef(): - if thing.kind != "op": - n_instrs += 1 - self.write_instr(self.instrs[thing.name]) + pass case parsing.Macro(): n_macros += 1 mac = self.macro_instrs[thing.name] @@ -910,6 +908,7 @@ def main() -> None: a = Generator(args.input) a.parse() # Raises SyntaxError on failure + a.desugar() a.analyze() # Prints messages and sets a.errors on failure if a.errors: sys.exit(f"Found {a.errors} errors") diff --git a/Tools/cases_generator/instructions.py b/Tools/cases_generator/instructions.py index 9143ae0db7be81..ee87ff36c2bfc7 100644 --- a/Tools/cases_generator/instructions.py +++ b/Tools/cases_generator/instructions.py @@ -45,7 +45,6 @@ class ActiveCacheEffect: TIER_TWO: typing.Final = 2 # Experimental tracing interpreter Tiers: typing.TypeAlias = typing.Literal[1, 2] - @dataclasses.dataclass class Instruction: """An instruction with additional data and code.""" @@ -255,6 +254,10 @@ class Component: instr: Instruction active_caches: list[ActiveCacheEffect] + @property + def name(self): + return self.instr.name + MacroParts = list[Component | parsing.CacheEffect] diff --git a/Tools/cases_generator/stacking.py b/Tools/cases_generator/stacking.py index dcdfc7ec054248..78ee01b807c988 100644 --- a/Tools/cases_generator/stacking.py +++ b/Tools/cases_generator/stacking.py @@ -368,7 +368,7 @@ def write_macro_instr( try: next_instr_is_set = write_components(parts, out, TIER_ONE, mac.cache_offset) except AssertionError as err: - raise AssertionError(f"Error writing macro {mac.name}") from err + raise AssertionError(f"Error writing macro {mac.name} {[part.name for part in mac.parts]}") from err if not parts[-1].instr.always_exits: if not next_instr_is_set and mac.cache_offset: out.emit(f"next_instr += {mac.cache_offset};") @@ -431,7 +431,7 @@ def write_components( # Use clone() since adjust_inverse() mutates final_offset mgr.adjust_inverse(mgr.final_offset.clone()) - if mgr.instr.name == "SAVE_CURRENT_IP": + if mgr.instr.name == "_SAVE_CURRENT_IP": next_instr_is_set = True if cache_offset: out.emit(f"next_instr += {cache_offset};")