From 2e5a1587edf532b1a467d966c04a1ff9746da9ca Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 14 Feb 2024 21:00:50 +0000 Subject: [PATCH 1/5] Split micro-ops if behavior depends on oparg&1 --- Include/internal/pycore_opcode_metadata.h | 22 +- Include/internal/pycore_uop_ids.h | 434 ++++++++-------- Include/internal/pycore_uop_metadata.h | 54 +- Python/executor_cases.c.h | 480 +++++++++++++++++- Python/generated_cases.c.h | 18 +- Python/optimizer.c | 3 + Python/optimizer_analysis.c | 5 +- Python/tier2_redundancy_eliminator_cases.c.h | 264 +++++++++- Tools/cases_generator/analyzer.py | 55 +- Tools/cases_generator/generators_common.py | 7 +- .../opcode_metadata_generator.py | 1 + Tools/cases_generator/stack.py | 20 +- Tools/cases_generator/tier2_generator.py | 21 + Tools/cases_generator/uop_id_generator.py | 10 +- 14 files changed, 1117 insertions(+), 277 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 6b60a6fbffdc5e..e6b6ef93efc6ac 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -519,7 +519,7 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { case CALL_ALLOC_AND_ENTER_INIT: return 1; case CALL_BOUND_METHOD_EXACT_ARGS: - return ((0) ? 1 : 0); + return 0; case CALL_BUILTIN_CLASS: return 1; case CALL_BUILTIN_FAST: @@ -551,7 +551,7 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { case CALL_METHOD_DESCRIPTOR_O: return 1; case CALL_PY_EXACT_ARGS: - return ((0) ? 1 : 0); + return 0; case CALL_PY_WITH_DEFAULTS: return 1; case CALL_STR_1: @@ -697,23 +697,23 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { case LOAD_ATTR_CLASS: return 1 + (oparg & 1); case LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN: - return 1 + ((0) ? 1 : 0); + return 1; case LOAD_ATTR_INSTANCE_VALUE: return 1 + (oparg & 1); case LOAD_ATTR_METHOD_LAZY_DICT: - return 1 + ((1) ? 1 : 0); + return 2; case LOAD_ATTR_METHOD_NO_DICT: - return 1 + ((1) ? 1 : 0); + return 2; case LOAD_ATTR_METHOD_WITH_VALUES: - return 1 + ((1) ? 1 : 0); + return 2; case LOAD_ATTR_MODULE: return 1 + (oparg & 1); case LOAD_ATTR_NONDESCRIPTOR_NO_DICT: - return 1 + ((0) ? 1 : 0); + return 1; case LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: - return 1 + ((0) ? 1 : 0); + return 1; case LOAD_ATTR_PROPERTY: - return 1 + ((0) ? 1 : 0); + return 1; case LOAD_ATTR_SLOT: return 1 + (oparg & 1); case LOAD_ATTR_WITH_HINT: @@ -749,7 +749,7 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { case LOAD_SUPER_ATTR: return 1 + (oparg & 1); case LOAD_SUPER_ATTR_ATTR: - return 1 + ((0) ? 1 : 0); + return 1; case LOAD_SUPER_ATTR_METHOD: return 2; case MAKE_CELL: @@ -911,6 +911,7 @@ enum InstructionFormat { #define HAS_ESCAPES_FLAG (512) #define HAS_PURE_FLAG (1024) #define HAS_PASSTHROUGH_FLAG (2048) +#define HAS_OPARG_AND_1_FLAG (4096) #define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ARG_FLAG)) #define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_CONST_FLAG)) #define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NAME_FLAG)) @@ -923,6 +924,7 @@ enum InstructionFormat { #define OPCODE_HAS_ESCAPES(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ESCAPES_FLAG)) #define OPCODE_HAS_PURE(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_PURE_FLAG)) #define OPCODE_HAS_PASSTHROUGH(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_PASSTHROUGH_FLAG)) +#define OPCODE_HAS_OPARG_AND_1(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_OPARG_AND_1_FLAG)) #define OPARG_FULL 0 #define OPARG_CACHE_1 1 diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 9bb537d355055d..583f6129c9d3d7 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -11,234 +11,256 @@ extern "C" { #define _EXIT_TRACE 300 #define _SET_IP 301 -#define _NOP NOP -#define _RESUME_CHECK RESUME_CHECK -#define _INSTRUMENTED_RESUME INSTRUMENTED_RESUME -#define _LOAD_FAST_CHECK LOAD_FAST_CHECK -#define _LOAD_FAST LOAD_FAST -#define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR -#define _LOAD_FAST_LOAD_FAST LOAD_FAST_LOAD_FAST -#define _LOAD_CONST LOAD_CONST -#define _STORE_FAST STORE_FAST -#define _STORE_FAST_LOAD_FAST STORE_FAST_LOAD_FAST -#define _STORE_FAST_STORE_FAST STORE_FAST_STORE_FAST -#define _POP_TOP POP_TOP -#define _PUSH_NULL PUSH_NULL -#define _END_SEND END_SEND -#define _UNARY_NEGATIVE UNARY_NEGATIVE -#define _UNARY_NOT UNARY_NOT -#define _TO_BOOL 302 -#define _TO_BOOL_BOOL TO_BOOL_BOOL -#define _TO_BOOL_INT TO_BOOL_INT -#define _TO_BOOL_LIST TO_BOOL_LIST -#define _TO_BOOL_NONE TO_BOOL_NONE -#define _TO_BOOL_STR TO_BOOL_STR -#define _TO_BOOL_ALWAYS_TRUE TO_BOOL_ALWAYS_TRUE -#define _UNARY_INVERT UNARY_INVERT -#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_SUBSCR 313 +#define _BEFORE_ASYNC_WITH BEFORE_ASYNC_WITH +#define _BEFORE_WITH BEFORE_WITH +#define _BINARY_OP 302 +#define _BINARY_OP_ADD_FLOAT 303 +#define _BINARY_OP_ADD_INT 304 +#define _BINARY_OP_ADD_UNICODE 305 +#define _BINARY_OP_MULTIPLY_FLOAT 306 +#define _BINARY_OP_MULTIPLY_INT 307 +#define _BINARY_OP_SUBTRACT_FLOAT 308 +#define _BINARY_OP_SUBTRACT_INT 309 #define _BINARY_SLICE BINARY_SLICE -#define _STORE_SLICE STORE_SLICE +#define _BINARY_SUBSCR 310 +#define _BINARY_SUBSCR_DICT BINARY_SUBSCR_DICT +#define _BINARY_SUBSCR_GETITEM BINARY_SUBSCR_GETITEM #define _BINARY_SUBSCR_LIST_INT BINARY_SUBSCR_LIST_INT #define _BINARY_SUBSCR_STR_INT BINARY_SUBSCR_STR_INT #define _BINARY_SUBSCR_TUPLE_INT BINARY_SUBSCR_TUPLE_INT -#define _BINARY_SUBSCR_DICT BINARY_SUBSCR_DICT -#define _BINARY_SUBSCR_GETITEM BINARY_SUBSCR_GETITEM -#define _LIST_APPEND LIST_APPEND -#define _SET_ADD SET_ADD -#define _STORE_SUBSCR 314 -#define _STORE_SUBSCR_LIST_INT STORE_SUBSCR_LIST_INT -#define _STORE_SUBSCR_DICT STORE_SUBSCR_DICT -#define _DELETE_SUBSCR DELETE_SUBSCR +#define _BUILD_CONST_KEY_MAP BUILD_CONST_KEY_MAP +#define _BUILD_LIST BUILD_LIST +#define _BUILD_MAP BUILD_MAP +#define _BUILD_SET BUILD_SET +#define _BUILD_SLICE BUILD_SLICE +#define _BUILD_STRING BUILD_STRING +#define _BUILD_TUPLE BUILD_TUPLE +#define _CALL 311 +#define _CALL_ALLOC_AND_ENTER_INIT CALL_ALLOC_AND_ENTER_INIT +#define _CALL_BUILTIN_CLASS CALL_BUILTIN_CLASS +#define _CALL_BUILTIN_FAST CALL_BUILTIN_FAST +#define _CALL_BUILTIN_FAST_WITH_KEYWORDS CALL_BUILTIN_FAST_WITH_KEYWORDS +#define _CALL_BUILTIN_O CALL_BUILTIN_O +#define _CALL_FUNCTION_EX CALL_FUNCTION_EX +#define _CALL_FUNCTION_EX_0 312 +#define _CALL_FUNCTION_EX_1 313 #define _CALL_INTRINSIC_1 CALL_INTRINSIC_1 #define _CALL_INTRINSIC_2 CALL_INTRINSIC_2 -#define _POP_FRAME 315 -#define _INSTRUMENTED_RETURN_VALUE INSTRUMENTED_RETURN_VALUE -#define _INSTRUMENTED_RETURN_CONST INSTRUMENTED_RETURN_CONST +#define _CALL_ISINSTANCE CALL_ISINSTANCE +#define _CALL_KW CALL_KW +#define _CALL_LEN CALL_LEN +#define _CALL_METHOD_DESCRIPTOR_FAST CALL_METHOD_DESCRIPTOR_FAST +#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS +#define _CALL_METHOD_DESCRIPTOR_NOARGS CALL_METHOD_DESCRIPTOR_NOARGS +#define _CALL_METHOD_DESCRIPTOR_O CALL_METHOD_DESCRIPTOR_O +#define _CALL_PY_WITH_DEFAULTS CALL_PY_WITH_DEFAULTS +#define _CALL_STR_1 CALL_STR_1 +#define _CALL_TUPLE_1 CALL_TUPLE_1 +#define _CALL_TYPE_1 CALL_TYPE_1 +#define _CHECK_ATTR_CLASS 314 +#define _CHECK_ATTR_METHOD_LAZY_DICT 315 +#define _CHECK_ATTR_MODULE 316 +#define _CHECK_ATTR_WITH_HINT 317 +#define _CHECK_BUILTINS 318 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 319 +#define _CHECK_EG_MATCH CHECK_EG_MATCH +#define _CHECK_EXC_MATCH CHECK_EXC_MATCH +#define _CHECK_FUNCTION_EXACT_ARGS 320 +#define _CHECK_GLOBALS 321 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES 322 +#define _CHECK_PEP_523 323 +#define _CHECK_STACK_SPACE 324 +#define _CHECK_VALIDITY 325 +#define _CHECK_VALIDITY_AND_SET_IP 326 +#define _COMPARE_OP 327 +#define _COMPARE_OP_FLOAT COMPARE_OP_FLOAT +#define _COMPARE_OP_INT COMPARE_OP_INT +#define _COMPARE_OP_STR COMPARE_OP_STR +#define _CONTAINS_OP CONTAINS_OP +#define _CONVERT_VALUE CONVERT_VALUE +#define _COPY COPY +#define _COPY_FREE_VARS COPY_FREE_VARS +#define _DELETE_ATTR DELETE_ATTR +#define _DELETE_DEREF DELETE_DEREF +#define _DELETE_FAST DELETE_FAST +#define _DELETE_GLOBAL DELETE_GLOBAL +#define _DELETE_NAME DELETE_NAME +#define _DELETE_SUBSCR DELETE_SUBSCR +#define _DICT_MERGE DICT_MERGE +#define _DICT_UPDATE DICT_UPDATE +#define _END_SEND END_SEND +#define _EXIT_INIT_CHECK EXIT_INIT_CHECK +#define _FORMAT_SIMPLE FORMAT_SIMPLE +#define _FORMAT_WITH_SPEC FORMAT_WITH_SPEC +#define _FOR_ITER 328 +#define _FOR_ITER_GEN FOR_ITER_GEN +#define _FOR_ITER_TIER_TWO 329 #define _GET_AITER GET_AITER #define _GET_ANEXT GET_ANEXT #define _GET_AWAITABLE GET_AWAITABLE -#define _SEND 316 -#define _SEND_GEN SEND_GEN +#define _GET_ITER GET_ITER +#define _GET_LEN GET_LEN +#define _GET_YIELD_FROM_ITER GET_YIELD_FROM_ITER +#define _GUARD_BOTH_FLOAT 330 +#define _GUARD_BOTH_INT 331 +#define _GUARD_BOTH_UNICODE 332 +#define _GUARD_BUILTINS_VERSION 333 +#define _GUARD_DORV_VALUES 334 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 335 +#define _GUARD_GLOBALS_VERSION 336 +#define _GUARD_IS_FALSE_POP 337 +#define _GUARD_IS_NONE_POP 338 +#define _GUARD_IS_NOT_NONE_POP 339 +#define _GUARD_IS_TRUE_POP 340 +#define _GUARD_KEYS_VERSION 341 +#define _GUARD_NOT_EXHAUSTED_LIST 342 +#define _GUARD_NOT_EXHAUSTED_RANGE 343 +#define _GUARD_NOT_EXHAUSTED_TUPLE 344 +#define _GUARD_TYPE_VERSION 345 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 346 +#define _INIT_CALL_PY_EXACT_ARGS 347 +#define _INSTRUMENTED_CALL INSTRUMENTED_CALL +#define _INSTRUMENTED_CALL_FUNCTION_EX INSTRUMENTED_CALL_FUNCTION_EX +#define _INSTRUMENTED_CALL_KW INSTRUMENTED_CALL_KW +#define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER +#define _INSTRUMENTED_INSTRUCTION INSTRUMENTED_INSTRUCTION +#define _INSTRUMENTED_JUMP_BACKWARD INSTRUMENTED_JUMP_BACKWARD +#define _INSTRUMENTED_JUMP_FORWARD INSTRUMENTED_JUMP_FORWARD +#define _INSTRUMENTED_LOAD_SUPER_ATTR INSTRUMENTED_LOAD_SUPER_ATTR +#define _INSTRUMENTED_LOAD_SUPER_ATTR_0 348 +#define _INSTRUMENTED_LOAD_SUPER_ATTR_1 349 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE INSTRUMENTED_POP_JUMP_IF_FALSE +#define _INSTRUMENTED_POP_JUMP_IF_NONE INSTRUMENTED_POP_JUMP_IF_NONE +#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE INSTRUMENTED_POP_JUMP_IF_NOT_NONE +#define _INSTRUMENTED_POP_JUMP_IF_TRUE INSTRUMENTED_POP_JUMP_IF_TRUE +#define _INSTRUMENTED_RESUME INSTRUMENTED_RESUME +#define _INSTRUMENTED_RETURN_CONST INSTRUMENTED_RETURN_CONST +#define _INSTRUMENTED_RETURN_VALUE INSTRUMENTED_RETURN_VALUE #define _INSTRUMENTED_YIELD_VALUE INSTRUMENTED_YIELD_VALUE -#define _POP_EXCEPT POP_EXCEPT +#define _INTERNAL_INCREMENT_OPT_COUNTER 350 +#define _IS_NONE 351 +#define _IS_OP IS_OP +#define _ITER_CHECK_LIST 352 +#define _ITER_CHECK_RANGE 353 +#define _ITER_CHECK_TUPLE 354 +#define _ITER_JUMP_LIST 355 +#define _ITER_JUMP_RANGE 356 +#define _ITER_JUMP_TUPLE 357 +#define _ITER_NEXT_LIST 358 +#define _ITER_NEXT_RANGE 359 +#define _ITER_NEXT_TUPLE 360 +#define _JUMP_BACKWARD JUMP_BACKWARD +#define _JUMP_TO_TOP 361 +#define _LIST_APPEND LIST_APPEND +#define _LIST_EXTEND LIST_EXTEND #define _LOAD_ASSERTION_ERROR LOAD_ASSERTION_ERROR +#define _LOAD_ATTR 362 +#define _LOAD_ATTR_0 363 +#define _LOAD_ATTR_1 364 +#define _LOAD_ATTR_CLASS 365 +#define _LOAD_ATTR_CLASS_0 366 +#define _LOAD_ATTR_CLASS_1 367 +#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN +#define _LOAD_ATTR_INSTANCE_VALUE 368 +#define _LOAD_ATTR_INSTANCE_VALUE_0 369 +#define _LOAD_ATTR_INSTANCE_VALUE_1 370 +#define _LOAD_ATTR_METHOD_LAZY_DICT 371 +#define _LOAD_ATTR_METHOD_NO_DICT 372 +#define _LOAD_ATTR_METHOD_WITH_VALUES 373 +#define _LOAD_ATTR_MODULE 374 +#define _LOAD_ATTR_MODULE_0 375 +#define _LOAD_ATTR_MODULE_1 376 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 377 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 378 +#define _LOAD_ATTR_PROPERTY LOAD_ATTR_PROPERTY +#define _LOAD_ATTR_SLOT 379 +#define _LOAD_ATTR_SLOT_0 380 +#define _LOAD_ATTR_SLOT_1 381 +#define _LOAD_ATTR_WITH_HINT 382 +#define _LOAD_ATTR_WITH_HINT_0 383 +#define _LOAD_ATTR_WITH_HINT_1 384 #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS -#define _STORE_NAME STORE_NAME -#define _DELETE_NAME DELETE_NAME -#define _UNPACK_SEQUENCE 317 -#define _UNPACK_SEQUENCE_TWO_TUPLE UNPACK_SEQUENCE_TWO_TUPLE -#define _UNPACK_SEQUENCE_TUPLE UNPACK_SEQUENCE_TUPLE -#define _UNPACK_SEQUENCE_LIST UNPACK_SEQUENCE_LIST -#define _UNPACK_EX UNPACK_EX -#define _STORE_ATTR 318 -#define _DELETE_ATTR DELETE_ATTR -#define _STORE_GLOBAL STORE_GLOBAL -#define _DELETE_GLOBAL DELETE_GLOBAL -#define _LOAD_LOCALS LOAD_LOCALS +#define _LOAD_CONST LOAD_CONST +#define _LOAD_CONST_INLINE 385 +#define _LOAD_CONST_INLINE_BORROW 386 +#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 387 +#define _LOAD_CONST_INLINE_WITH_NULL 388 +#define _LOAD_DEREF LOAD_DEREF +#define _LOAD_FAST LOAD_FAST +#define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR +#define _LOAD_FAST_CHECK LOAD_FAST_CHECK +#define _LOAD_FAST_LOAD_FAST LOAD_FAST_LOAD_FAST +#define _LOAD_FROM_DICT_OR_DEREF LOAD_FROM_DICT_OR_DEREF #define _LOAD_FROM_DICT_OR_GLOBALS LOAD_FROM_DICT_OR_GLOBALS +#define _LOAD_GLOBAL 389 +#define _LOAD_GLOBAL_0 390 +#define _LOAD_GLOBAL_1 391 +#define _LOAD_GLOBAL_BUILTINS 392 +#define _LOAD_GLOBAL_BUILTINS_0 393 +#define _LOAD_GLOBAL_BUILTINS_1 394 +#define _LOAD_GLOBAL_MODULE 395 +#define _LOAD_GLOBAL_MODULE_0 396 +#define _LOAD_GLOBAL_MODULE_1 397 +#define _LOAD_LOCALS LOAD_LOCALS #define _LOAD_NAME LOAD_NAME -#define _LOAD_GLOBAL 319 -#define _GUARD_GLOBALS_VERSION 320 -#define _GUARD_BUILTINS_VERSION 321 -#define _LOAD_GLOBAL_MODULE 322 -#define _LOAD_GLOBAL_BUILTINS 323 -#define _DELETE_FAST DELETE_FAST -#define _MAKE_CELL MAKE_CELL -#define _DELETE_DEREF DELETE_DEREF -#define _LOAD_FROM_DICT_OR_DEREF LOAD_FROM_DICT_OR_DEREF -#define _LOAD_DEREF LOAD_DEREF -#define _STORE_DEREF STORE_DEREF -#define _COPY_FREE_VARS COPY_FREE_VARS -#define _BUILD_STRING BUILD_STRING -#define _BUILD_TUPLE BUILD_TUPLE -#define _BUILD_LIST BUILD_LIST -#define _LIST_EXTEND LIST_EXTEND -#define _SET_UPDATE SET_UPDATE -#define _BUILD_SET BUILD_SET -#define _BUILD_MAP BUILD_MAP -#define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS -#define _BUILD_CONST_KEY_MAP BUILD_CONST_KEY_MAP -#define _DICT_UPDATE DICT_UPDATE -#define _DICT_MERGE DICT_MERGE -#define _MAP_ADD MAP_ADD -#define _INSTRUMENTED_LOAD_SUPER_ATTR INSTRUMENTED_LOAD_SUPER_ATTR #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR #define _LOAD_SUPER_ATTR_METHOD LOAD_SUPER_ATTR_METHOD -#define _LOAD_ATTR 324 -#define _GUARD_TYPE_VERSION 325 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES 326 -#define _LOAD_ATTR_INSTANCE_VALUE 327 -#define _CHECK_ATTR_MODULE 328 -#define _LOAD_ATTR_MODULE 329 -#define _CHECK_ATTR_WITH_HINT 330 -#define _LOAD_ATTR_WITH_HINT 331 -#define _LOAD_ATTR_SLOT 332 -#define _CHECK_ATTR_CLASS 333 -#define _LOAD_ATTR_CLASS 334 -#define _LOAD_ATTR_PROPERTY LOAD_ATTR_PROPERTY -#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN -#define _GUARD_DORV_VALUES 335 -#define _STORE_ATTR_INSTANCE_VALUE 336 -#define _STORE_ATTR_WITH_HINT STORE_ATTR_WITH_HINT -#define _STORE_ATTR_SLOT 337 -#define _COMPARE_OP 338 -#define _COMPARE_OP_FLOAT COMPARE_OP_FLOAT -#define _COMPARE_OP_INT COMPARE_OP_INT -#define _COMPARE_OP_STR COMPARE_OP_STR -#define _IS_OP IS_OP -#define _CONTAINS_OP CONTAINS_OP -#define _CHECK_EG_MATCH CHECK_EG_MATCH -#define _CHECK_EXC_MATCH CHECK_EXC_MATCH -#define _JUMP_BACKWARD JUMP_BACKWARD -#define _POP_JUMP_IF_FALSE 339 -#define _POP_JUMP_IF_TRUE 340 -#define _IS_NONE 341 -#define _GET_LEN GET_LEN +#define _MAKE_CELL MAKE_CELL +#define _MAKE_FUNCTION MAKE_FUNCTION +#define _MAP_ADD MAP_ADD #define _MATCH_CLASS MATCH_CLASS +#define _MATCH_KEYS MATCH_KEYS #define _MATCH_MAPPING MATCH_MAPPING #define _MATCH_SEQUENCE MATCH_SEQUENCE -#define _MATCH_KEYS MATCH_KEYS -#define _GET_ITER GET_ITER -#define _GET_YIELD_FROM_ITER GET_YIELD_FROM_ITER -#define _FOR_ITER 342 -#define _FOR_ITER_TIER_TWO 343 -#define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER -#define _ITER_CHECK_LIST 344 -#define _ITER_JUMP_LIST 345 -#define _GUARD_NOT_EXHAUSTED_LIST 346 -#define _ITER_NEXT_LIST 347 -#define _ITER_CHECK_TUPLE 348 -#define _ITER_JUMP_TUPLE 349 -#define _GUARD_NOT_EXHAUSTED_TUPLE 350 -#define _ITER_NEXT_TUPLE 351 -#define _ITER_CHECK_RANGE 352 -#define _ITER_JUMP_RANGE 353 -#define _GUARD_NOT_EXHAUSTED_RANGE 354 -#define _ITER_NEXT_RANGE 355 -#define _FOR_ITER_GEN FOR_ITER_GEN -#define _BEFORE_ASYNC_WITH BEFORE_ASYNC_WITH -#define _BEFORE_WITH BEFORE_WITH -#define _WITH_EXCEPT_START WITH_EXCEPT_START +#define _NOP NOP +#define _POP_EXCEPT POP_EXCEPT +#define _POP_FRAME 398 +#define _POP_JUMP_IF_FALSE 399 +#define _POP_JUMP_IF_TRUE 400 +#define _POP_TOP POP_TOP #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 356 -#define _GUARD_KEYS_VERSION 357 -#define _LOAD_ATTR_METHOD_WITH_VALUES 358 -#define _LOAD_ATTR_METHOD_NO_DICT 359 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 360 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 361 -#define _CHECK_ATTR_METHOD_LAZY_DICT 362 -#define _LOAD_ATTR_METHOD_LAZY_DICT 363 -#define _INSTRUMENTED_CALL INSTRUMENTED_CALL -#define _CALL 364 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 365 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 366 -#define _CHECK_PEP_523 367 -#define _CHECK_FUNCTION_EXACT_ARGS 368 -#define _CHECK_STACK_SPACE 369 -#define _INIT_CALL_PY_EXACT_ARGS 370 -#define _PUSH_FRAME 371 -#define _CALL_PY_WITH_DEFAULTS CALL_PY_WITH_DEFAULTS -#define _CALL_TYPE_1 CALL_TYPE_1 -#define _CALL_STR_1 CALL_STR_1 -#define _CALL_TUPLE_1 CALL_TUPLE_1 -#define _CALL_ALLOC_AND_ENTER_INIT CALL_ALLOC_AND_ENTER_INIT -#define _EXIT_INIT_CHECK EXIT_INIT_CHECK -#define _CALL_BUILTIN_CLASS CALL_BUILTIN_CLASS -#define _CALL_BUILTIN_O CALL_BUILTIN_O -#define _CALL_BUILTIN_FAST CALL_BUILTIN_FAST -#define _CALL_BUILTIN_FAST_WITH_KEYWORDS CALL_BUILTIN_FAST_WITH_KEYWORDS -#define _CALL_LEN CALL_LEN -#define _CALL_ISINSTANCE CALL_ISINSTANCE -#define _CALL_METHOD_DESCRIPTOR_O CALL_METHOD_DESCRIPTOR_O -#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS -#define _CALL_METHOD_DESCRIPTOR_NOARGS CALL_METHOD_DESCRIPTOR_NOARGS -#define _CALL_METHOD_DESCRIPTOR_FAST CALL_METHOD_DESCRIPTOR_FAST -#define _INSTRUMENTED_CALL_KW INSTRUMENTED_CALL_KW -#define _CALL_KW CALL_KW -#define _INSTRUMENTED_CALL_FUNCTION_EX INSTRUMENTED_CALL_FUNCTION_EX -#define _CALL_FUNCTION_EX CALL_FUNCTION_EX -#define _MAKE_FUNCTION MAKE_FUNCTION +#define _PUSH_FRAME 401 +#define _PUSH_NULL PUSH_NULL +#define _RESUME_CHECK RESUME_CHECK +#define _SAVE_RETURN_OFFSET 402 +#define _SEND 403 +#define _SEND_GEN SEND_GEN +#define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS +#define _SET_ADD SET_ADD #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE -#define _BUILD_SLICE BUILD_SLICE -#define _CONVERT_VALUE CONVERT_VALUE -#define _FORMAT_SIMPLE FORMAT_SIMPLE -#define _FORMAT_WITH_SPEC FORMAT_WITH_SPEC -#define _COPY COPY -#define _BINARY_OP 372 +#define _SET_UPDATE SET_UPDATE +#define _STORE_ATTR 404 +#define _STORE_ATTR_INSTANCE_VALUE 405 +#define _STORE_ATTR_SLOT 406 +#define _STORE_ATTR_WITH_HINT STORE_ATTR_WITH_HINT +#define _STORE_DEREF STORE_DEREF +#define _STORE_FAST STORE_FAST +#define _STORE_FAST_LOAD_FAST STORE_FAST_LOAD_FAST +#define _STORE_FAST_STORE_FAST STORE_FAST_STORE_FAST +#define _STORE_GLOBAL STORE_GLOBAL +#define _STORE_NAME STORE_NAME +#define _STORE_SLICE STORE_SLICE +#define _STORE_SUBSCR 407 +#define _STORE_SUBSCR_DICT STORE_SUBSCR_DICT +#define _STORE_SUBSCR_LIST_INT STORE_SUBSCR_LIST_INT #define _SWAP SWAP -#define _INSTRUMENTED_INSTRUCTION INSTRUMENTED_INSTRUCTION -#define _INSTRUMENTED_JUMP_FORWARD INSTRUMENTED_JUMP_FORWARD -#define _INSTRUMENTED_JUMP_BACKWARD INSTRUMENTED_JUMP_BACKWARD -#define _INSTRUMENTED_POP_JUMP_IF_TRUE INSTRUMENTED_POP_JUMP_IF_TRUE -#define _INSTRUMENTED_POP_JUMP_IF_FALSE INSTRUMENTED_POP_JUMP_IF_FALSE -#define _INSTRUMENTED_POP_JUMP_IF_NONE INSTRUMENTED_POP_JUMP_IF_NONE -#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE INSTRUMENTED_POP_JUMP_IF_NOT_NONE -#define _GUARD_IS_TRUE_POP 373 -#define _GUARD_IS_FALSE_POP 374 -#define _GUARD_IS_NONE_POP 375 -#define _GUARD_IS_NOT_NONE_POP 376 -#define _JUMP_TO_TOP 377 -#define _SAVE_RETURN_OFFSET 378 -#define _CHECK_VALIDITY 379 -#define _LOAD_CONST_INLINE 380 -#define _LOAD_CONST_INLINE_BORROW 381 -#define _LOAD_CONST_INLINE_WITH_NULL 382 -#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 383 -#define _CHECK_GLOBALS 384 -#define _CHECK_BUILTINS 385 -#define _INTERNAL_INCREMENT_OPT_COUNTER 386 -#define _CHECK_VALIDITY_AND_SET_IP 387 -#define MAX_UOP_ID 387 +#define _TO_BOOL 408 +#define _TO_BOOL_ALWAYS_TRUE TO_BOOL_ALWAYS_TRUE +#define _TO_BOOL_BOOL TO_BOOL_BOOL +#define _TO_BOOL_INT TO_BOOL_INT +#define _TO_BOOL_LIST TO_BOOL_LIST +#define _TO_BOOL_NONE TO_BOOL_NONE +#define _TO_BOOL_STR TO_BOOL_STR +#define _UNARY_INVERT UNARY_INVERT +#define _UNARY_NEGATIVE UNARY_NEGATIVE +#define _UNARY_NOT UNARY_NOT +#define _UNPACK_EX UNPACK_EX +#define _UNPACK_SEQUENCE 409 +#define _UNPACK_SEQUENCE_LIST UNPACK_SEQUENCE_LIST +#define _UNPACK_SEQUENCE_TUPLE UNPACK_SEQUENCE_TUPLE +#define _UNPACK_SEQUENCE_TWO_TUPLE UNPACK_SEQUENCE_TWO_TUPLE +#define _WITH_EXCEPT_START WITH_EXCEPT_START +#define MAX_UOP_ID 409 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 163a0320aa2298..a305074cbed914 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -85,11 +85,17 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_LOAD_LOCALS] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_LOAD_FROM_DICT_OR_GLOBALS] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_LOAD_NAME] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_LOAD_GLOBAL] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_LOAD_GLOBAL_0] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_LOAD_GLOBAL_1] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_LOAD_GLOBAL] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_OPARG_AND_1_FLAG, [_GUARD_GLOBALS_VERSION] = HAS_DEOPT_FLAG, [_GUARD_BUILTINS_VERSION] = HAS_DEOPT_FLAG, - [_LOAD_GLOBAL_MODULE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_LOAD_GLOBAL_BUILTINS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_GLOBAL_MODULE_0] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_GLOBAL_MODULE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_GLOBAL_MODULE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_OPARG_AND_1_FLAG, + [_LOAD_GLOBAL_BUILTINS_0] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_GLOBAL_BUILTINS_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_GLOBAL_BUILTINS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_OPARG_AND_1_FLAG, [_DELETE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ERROR_FLAG, [_MAKE_CELL] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_DELETE_DEREF] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -111,17 +117,29 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_MAP_ADD] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_LOAD_SUPER_ATTR_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_LOAD_SUPER_ATTR_METHOD] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_LOAD_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_LOAD_ATTR_0] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_LOAD_ATTR_1] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_LOAD_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_OPARG_AND_1_FLAG, [_GUARD_TYPE_VERSION] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, [_CHECK_MANAGED_OBJECT_HAS_VALUES] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, - [_LOAD_ATTR_INSTANCE_VALUE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_ATTR_INSTANCE_VALUE_0] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_ATTR_INSTANCE_VALUE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_ATTR_INSTANCE_VALUE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_OPARG_AND_1_FLAG, [_CHECK_ATTR_MODULE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, - [_LOAD_ATTR_MODULE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_ATTR_MODULE_0] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_ATTR_MODULE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_ATTR_MODULE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_OPARG_AND_1_FLAG, [_CHECK_ATTR_WITH_HINT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG | HAS_PASSTHROUGH_FLAG, - [_LOAD_ATTR_WITH_HINT] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, - [_LOAD_ATTR_SLOT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_ATTR_WITH_HINT_0] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, + [_LOAD_ATTR_WITH_HINT_1] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, + [_LOAD_ATTR_WITH_HINT] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG | HAS_OPARG_AND_1_FLAG, + [_LOAD_ATTR_SLOT_0] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_ATTR_SLOT_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_ATTR_SLOT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_OPARG_AND_1_FLAG, [_CHECK_ATTR_CLASS] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, - [_LOAD_ATTR_CLASS] = HAS_ARG_FLAG, + [_LOAD_ATTR_CLASS_0] = HAS_ARG_FLAG, + [_LOAD_ATTR_CLASS_1] = HAS_ARG_FLAG, + [_LOAD_ATTR_CLASS] = HAS_ARG_FLAG | HAS_OPARG_AND_1_FLAG, [_GUARD_DORV_VALUES] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, [_STORE_ATTR_INSTANCE_VALUE] = HAS_ESCAPES_FLAG, [_STORE_ATTR_SLOT] = HAS_ESCAPES_FLAG, @@ -326,16 +344,28 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_LIST_EXTEND] = "_LIST_EXTEND", [_LOAD_ASSERTION_ERROR] = "_LOAD_ASSERTION_ERROR", [_LOAD_ATTR] = "_LOAD_ATTR", + [_LOAD_ATTR_0] = "_LOAD_ATTR_0", + [_LOAD_ATTR_1] = "_LOAD_ATTR_1", [_LOAD_ATTR_CLASS] = "_LOAD_ATTR_CLASS", + [_LOAD_ATTR_CLASS_0] = "_LOAD_ATTR_CLASS_0", + [_LOAD_ATTR_CLASS_1] = "_LOAD_ATTR_CLASS_1", [_LOAD_ATTR_INSTANCE_VALUE] = "_LOAD_ATTR_INSTANCE_VALUE", + [_LOAD_ATTR_INSTANCE_VALUE_0] = "_LOAD_ATTR_INSTANCE_VALUE_0", + [_LOAD_ATTR_INSTANCE_VALUE_1] = "_LOAD_ATTR_INSTANCE_VALUE_1", [_LOAD_ATTR_METHOD_LAZY_DICT] = "_LOAD_ATTR_METHOD_LAZY_DICT", [_LOAD_ATTR_METHOD_NO_DICT] = "_LOAD_ATTR_METHOD_NO_DICT", [_LOAD_ATTR_METHOD_WITH_VALUES] = "_LOAD_ATTR_METHOD_WITH_VALUES", [_LOAD_ATTR_MODULE] = "_LOAD_ATTR_MODULE", + [_LOAD_ATTR_MODULE_0] = "_LOAD_ATTR_MODULE_0", + [_LOAD_ATTR_MODULE_1] = "_LOAD_ATTR_MODULE_1", [_LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = "_LOAD_ATTR_NONDESCRIPTOR_NO_DICT", [_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = "_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", [_LOAD_ATTR_SLOT] = "_LOAD_ATTR_SLOT", + [_LOAD_ATTR_SLOT_0] = "_LOAD_ATTR_SLOT_0", + [_LOAD_ATTR_SLOT_1] = "_LOAD_ATTR_SLOT_1", [_LOAD_ATTR_WITH_HINT] = "_LOAD_ATTR_WITH_HINT", + [_LOAD_ATTR_WITH_HINT_0] = "_LOAD_ATTR_WITH_HINT_0", + [_LOAD_ATTR_WITH_HINT_1] = "_LOAD_ATTR_WITH_HINT_1", [_LOAD_BUILD_CLASS] = "_LOAD_BUILD_CLASS", [_LOAD_CONST] = "_LOAD_CONST", [_LOAD_CONST_INLINE] = "_LOAD_CONST_INLINE", @@ -350,8 +380,14 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_LOAD_FROM_DICT_OR_DEREF] = "_LOAD_FROM_DICT_OR_DEREF", [_LOAD_FROM_DICT_OR_GLOBALS] = "_LOAD_FROM_DICT_OR_GLOBALS", [_LOAD_GLOBAL] = "_LOAD_GLOBAL", + [_LOAD_GLOBAL_0] = "_LOAD_GLOBAL_0", + [_LOAD_GLOBAL_1] = "_LOAD_GLOBAL_1", [_LOAD_GLOBAL_BUILTINS] = "_LOAD_GLOBAL_BUILTINS", + [_LOAD_GLOBAL_BUILTINS_0] = "_LOAD_GLOBAL_BUILTINS_0", + [_LOAD_GLOBAL_BUILTINS_1] = "_LOAD_GLOBAL_BUILTINS_1", [_LOAD_GLOBAL_MODULE] = "_LOAD_GLOBAL_MODULE", + [_LOAD_GLOBAL_MODULE_0] = "_LOAD_GLOBAL_MODULE_0", + [_LOAD_GLOBAL_MODULE_1] = "_LOAD_GLOBAL_MODULE_1", [_LOAD_LOCALS] = "_LOAD_LOCALS", [_LOAD_NAME] = "_LOAD_NAME", [_LOAD_SUPER_ATTR_ATTR] = "_LOAD_SUPER_ATTR_ATTR", diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 7a0e0e43be019c..70d91ffe7d4b76 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1087,6 +1087,93 @@ break; } + case _LOAD_GLOBAL_0: { + PyObject *res; + PyObject *null = NULL; + oparg = CURRENT_OPARG(); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); + if (PyDict_CheckExact(GLOBALS()) + && PyDict_CheckExact(BUILTINS())) + { + res = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(), + (PyDictObject *)BUILTINS(), + name); + if (res == NULL) { + if (!_PyErr_Occurred(tstate)) { + /* _PyDict_LoadGlobal() returns NULL without raising + * an exception if the key doesn't exist */ + _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } + if (true) goto error_tier_two; + } + Py_INCREF(res); + } + else { + /* Slow-path if globals or builtins is not a dict */ + /* namespace 1: globals */ + if (PyMapping_GetOptionalItem(GLOBALS(), name, &res) < 0) goto error_tier_two; + if (res == NULL) { + /* namespace 2: builtins */ + if (PyMapping_GetOptionalItem(BUILTINS(), name, &res) < 0) goto error_tier_two; + if (res == NULL) { + _PyEval_FormatExcCheckArg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + if (true) goto error_tier_two; + } + } + } + null = NULL; + stack_pointer[0] = res; + stack_pointer += 1; + break; + } + + case _LOAD_GLOBAL_1: { + PyObject *res; + PyObject *null = NULL; + oparg = CURRENT_OPARG(); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); + if (PyDict_CheckExact(GLOBALS()) + && PyDict_CheckExact(BUILTINS())) + { + res = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(), + (PyDictObject *)BUILTINS(), + name); + if (res == NULL) { + if (!_PyErr_Occurred(tstate)) { + /* _PyDict_LoadGlobal() returns NULL without raising + * an exception if the key doesn't exist */ + _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } + if (true) goto error_tier_two; + } + Py_INCREF(res); + } + else { + /* Slow-path if globals or builtins is not a dict */ + /* namespace 1: globals */ + if (PyMapping_GetOptionalItem(GLOBALS(), name, &res) < 0) goto error_tier_two; + if (res == NULL) { + /* namespace 2: builtins */ + if (PyMapping_GetOptionalItem(BUILTINS(), name, &res) < 0) goto error_tier_two; + if (res == NULL) { + _PyEval_FormatExcCheckArg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + if (true) goto error_tier_two; + } + } + } + null = NULL; + stack_pointer[0] = res; + stack_pointer[1] = null; + stack_pointer += 2; + break; + } + case _LOAD_GLOBAL: { PyObject *res; PyObject *null = NULL; @@ -1149,6 +1236,41 @@ break; } + case _LOAD_GLOBAL_MODULE_0: { + PyObject *res; + PyObject *null = NULL; + oparg = CURRENT_OPARG(); + uint16_t index = (uint16_t)CURRENT_OPERAND(); + PyDictObject *dict = (PyDictObject *)GLOBALS(); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); + res = entries[index].me_value; + if (res == NULL) goto deoptimize; + Py_INCREF(res); + STAT_INC(LOAD_GLOBAL, hit); + null = NULL; + stack_pointer[0] = res; + stack_pointer += 1; + break; + } + + case _LOAD_GLOBAL_MODULE_1: { + PyObject *res; + PyObject *null = NULL; + oparg = CURRENT_OPARG(); + uint16_t index = (uint16_t)CURRENT_OPERAND(); + PyDictObject *dict = (PyDictObject *)GLOBALS(); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); + res = entries[index].me_value; + if (res == NULL) goto deoptimize; + Py_INCREF(res); + STAT_INC(LOAD_GLOBAL, hit); + null = NULL; + stack_pointer[0] = res; + stack_pointer[1] = null; + stack_pointer += 2; + break; + } + case _LOAD_GLOBAL_MODULE: { PyObject *res; PyObject *null = NULL; @@ -1167,6 +1289,41 @@ break; } + case _LOAD_GLOBAL_BUILTINS_0: { + PyObject *res; + PyObject *null = NULL; + oparg = CURRENT_OPARG(); + uint16_t index = (uint16_t)CURRENT_OPERAND(); + PyDictObject *bdict = (PyDictObject *)BUILTINS(); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys); + res = entries[index].me_value; + if (res == NULL) goto deoptimize; + Py_INCREF(res); + STAT_INC(LOAD_GLOBAL, hit); + null = NULL; + stack_pointer[0] = res; + stack_pointer += 1; + break; + } + + case _LOAD_GLOBAL_BUILTINS_1: { + PyObject *res; + PyObject *null = NULL; + oparg = CURRENT_OPARG(); + uint16_t index = (uint16_t)CURRENT_OPERAND(); + PyDictObject *bdict = (PyDictObject *)BUILTINS(); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys); + res = entries[index].me_value; + if (res == NULL) goto deoptimize; + Py_INCREF(res); + STAT_INC(LOAD_GLOBAL, hit); + null = NULL; + stack_pointer[0] = res; + stack_pointer[1] = null; + stack_pointer += 2; + break; + } + case _LOAD_GLOBAL_BUILTINS: { PyObject *res; PyObject *null = NULL; @@ -1512,6 +1669,10 @@ break; } + /* _INSTRUMENTED_LOAD_SUPER_ATTR_0 is not a viable micro-op for tier 2 */ + + /* _INSTRUMENTED_LOAD_SUPER_ATTR_1 is not a viable micro-op for tier 2 */ + /* _INSTRUMENTED_LOAD_SUPER_ATTR is not a viable micro-op for tier 2 */ case _LOAD_SUPER_ATTR_ATTR: { @@ -1534,7 +1695,7 @@ Py_DECREF(self); if (attr == NULL) goto pop_3_error_tier_two; stack_pointer[-3] = attr; - stack_pointer += -2 + ((0) ? 1 : 0); + stack_pointer += -2; break; } @@ -1575,6 +1736,88 @@ break; } + case _LOAD_ATTR_0: { + PyObject *owner; + PyObject *attr; + PyObject *self_or_null = NULL; + oparg = CURRENT_OPARG(); + owner = stack_pointer[-1]; + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); + if (0 ) { + /* Designed to work in tandem with CALL, pushes two values. */ + attr = NULL; + if (_PyObject_GetMethod(owner, name, &attr)) { + /* We can bypass temporary bound method object. + meth is unbound method and obj is self. + meth | self | arg1 | ... | argN + */ + assert(attr != NULL); // No errors on this branch + self_or_null = owner; // Transfer ownership + } + else { + /* meth is not an unbound method (but a regular attr, or + something was returned by a descriptor protocol). Set + the second element of the stack to NULL, to signal + CALL that it's not a method call. + meth | NULL | arg1 | ... | argN + */ + Py_DECREF(owner); + if (attr == NULL) goto pop_1_error_tier_two; + self_or_null = NULL; + } + } + else { + /* Classic, pushes one value. */ + attr = PyObject_GetAttr(owner, name); + Py_DECREF(owner); + if (attr == NULL) goto pop_1_error_tier_two; + } + stack_pointer[-1] = attr; + break; + } + + case _LOAD_ATTR_1: { + PyObject *owner; + PyObject *attr; + PyObject *self_or_null = NULL; + oparg = CURRENT_OPARG(); + owner = stack_pointer[-1]; + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); + if (1 ) { + /* Designed to work in tandem with CALL, pushes two values. */ + attr = NULL; + if (_PyObject_GetMethod(owner, name, &attr)) { + /* We can bypass temporary bound method object. + meth is unbound method and obj is self. + meth | self | arg1 | ... | argN + */ + assert(attr != NULL); // No errors on this branch + self_or_null = owner; // Transfer ownership + } + else { + /* meth is not an unbound method (but a regular attr, or + something was returned by a descriptor protocol). Set + the second element of the stack to NULL, to signal + CALL that it's not a method call. + meth | NULL | arg1 | ... | argN + */ + Py_DECREF(owner); + if (attr == NULL) goto pop_1_error_tier_two; + self_or_null = NULL; + } + } + else { + /* Classic, pushes one value. */ + attr = PyObject_GetAttr(owner, name); + Py_DECREF(owner); + if (attr == NULL) goto pop_1_error_tier_two; + } + stack_pointer[-1] = attr; + stack_pointer[0] = self_or_null; + stack_pointer += 1; + break; + } + case _LOAD_ATTR: { PyObject *owner; PyObject *attr; @@ -1637,6 +1880,44 @@ break; } + case _LOAD_ATTR_INSTANCE_VALUE_0: { + PyObject *owner; + PyObject *attr; + PyObject *null = NULL; + oparg = CURRENT_OPARG(); + owner = stack_pointer[-1]; + uint16_t index = (uint16_t)CURRENT_OPERAND(); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + attr = _PyDictOrValues_GetValues(dorv)->values[index]; + if (attr == NULL) goto deoptimize; + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(attr); + null = NULL; + Py_DECREF(owner); + stack_pointer[-1] = attr; + break; + } + + case _LOAD_ATTR_INSTANCE_VALUE_1: { + PyObject *owner; + PyObject *attr; + PyObject *null = NULL; + oparg = CURRENT_OPARG(); + owner = stack_pointer[-1]; + uint16_t index = (uint16_t)CURRENT_OPERAND(); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + attr = _PyDictOrValues_GetValues(dorv)->values[index]; + if (attr == NULL) goto deoptimize; + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(attr); + null = NULL; + Py_DECREF(owner); + stack_pointer[-1] = attr; + stack_pointer[0] = null; + stack_pointer += 1; + break; + } + case _LOAD_ATTR_INSTANCE_VALUE: { PyObject *owner; PyObject *attr; @@ -1668,6 +1949,50 @@ break; } + case _LOAD_ATTR_MODULE_0: { + PyObject *owner; + PyObject *attr; + PyObject *null = NULL; + oparg = CURRENT_OPARG(); + owner = stack_pointer[-1]; + uint16_t index = (uint16_t)CURRENT_OPERAND(); + PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; + assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE); + assert(index < dict->ma_keys->dk_nentries); + PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + index; + attr = ep->me_value; + if (attr == NULL) goto deoptimize; + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(attr); + null = NULL; + Py_DECREF(owner); + stack_pointer[-1] = attr; + break; + } + + case _LOAD_ATTR_MODULE_1: { + PyObject *owner; + PyObject *attr; + PyObject *null = NULL; + oparg = CURRENT_OPARG(); + owner = stack_pointer[-1]; + uint16_t index = (uint16_t)CURRENT_OPERAND(); + PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; + assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE); + assert(index < dict->ma_keys->dk_nentries); + PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + index; + attr = ep->me_value; + if (attr == NULL) goto deoptimize; + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(attr); + null = NULL; + Py_DECREF(owner); + stack_pointer[-1] = attr; + stack_pointer[0] = null; + stack_pointer += 1; + break; + } + case _LOAD_ATTR_MODULE: { PyObject *owner; PyObject *attr; @@ -1703,6 +2028,68 @@ break; } + case _LOAD_ATTR_WITH_HINT_0: { + PyObject *owner; + PyObject *attr; + PyObject *null = NULL; + oparg = CURRENT_OPARG(); + owner = stack_pointer[-1]; + uint16_t hint = (uint16_t)CURRENT_OPERAND(); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); + if (hint >= (size_t)dict->ma_keys->dk_nentries) goto deoptimize; + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); + if (DK_IS_UNICODE(dict->ma_keys)) { + PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; + if (ep->me_key != name) goto deoptimize; + attr = ep->me_value; + } + else { + PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint; + if (ep->me_key != name) goto deoptimize; + attr = ep->me_value; + } + if (attr == NULL) goto deoptimize; + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(attr); + null = NULL; + Py_DECREF(owner); + stack_pointer[-1] = attr; + break; + } + + case _LOAD_ATTR_WITH_HINT_1: { + PyObject *owner; + PyObject *attr; + PyObject *null = NULL; + oparg = CURRENT_OPARG(); + owner = stack_pointer[-1]; + uint16_t hint = (uint16_t)CURRENT_OPERAND(); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); + if (hint >= (size_t)dict->ma_keys->dk_nentries) goto deoptimize; + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); + if (DK_IS_UNICODE(dict->ma_keys)) { + PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; + if (ep->me_key != name) goto deoptimize; + attr = ep->me_value; + } + else { + PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint; + if (ep->me_key != name) goto deoptimize; + attr = ep->me_value; + } + if (attr == NULL) goto deoptimize; + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(attr); + null = NULL; + Py_DECREF(owner); + stack_pointer[-1] = attr; + stack_pointer[0] = null; + stack_pointer += 1; + break; + } + case _LOAD_ATTR_WITH_HINT: { PyObject *owner; PyObject *attr; @@ -1735,6 +2122,44 @@ break; } + case _LOAD_ATTR_SLOT_0: { + PyObject *owner; + PyObject *attr; + PyObject *null = NULL; + oparg = CURRENT_OPARG(); + owner = stack_pointer[-1]; + uint16_t index = (uint16_t)CURRENT_OPERAND(); + char *addr = (char *)owner + index; + attr = *(PyObject **)addr; + if (attr == NULL) goto deoptimize; + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(attr); + null = NULL; + Py_DECREF(owner); + stack_pointer[-1] = attr; + break; + } + + case _LOAD_ATTR_SLOT_1: { + PyObject *owner; + PyObject *attr; + PyObject *null = NULL; + oparg = CURRENT_OPARG(); + owner = stack_pointer[-1]; + uint16_t index = (uint16_t)CURRENT_OPERAND(); + char *addr = (char *)owner + index; + attr = *(PyObject **)addr; + if (attr == NULL) goto deoptimize; + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(attr); + null = NULL; + Py_DECREF(owner); + stack_pointer[-1] = attr; + stack_pointer[0] = null; + stack_pointer += 1; + break; + } + case _LOAD_ATTR_SLOT: { PyObject *owner; PyObject *attr; @@ -1765,6 +2190,40 @@ break; } + case _LOAD_ATTR_CLASS_0: { + PyObject *owner; + PyObject *attr; + PyObject *null = NULL; + oparg = CURRENT_OPARG(); + owner = stack_pointer[-1]; + PyObject *descr = (PyObject *)CURRENT_OPERAND(); + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + attr = Py_NewRef(descr); + null = NULL; + Py_DECREF(owner); + stack_pointer[-1] = attr; + break; + } + + case _LOAD_ATTR_CLASS_1: { + PyObject *owner; + PyObject *attr; + PyObject *null = NULL; + oparg = CURRENT_OPARG(); + owner = stack_pointer[-1]; + PyObject *descr = (PyObject *)CURRENT_OPERAND(); + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + attr = Py_NewRef(descr); + null = NULL; + Py_DECREF(owner); + stack_pointer[-1] = attr; + stack_pointer[0] = null; + stack_pointer += 1; + break; + } + case _LOAD_ATTR_CLASS: { PyObject *owner; PyObject *attr; @@ -2466,8 +2925,8 @@ assert(_PyType_HasFeature(Py_TYPE(attr), Py_TPFLAGS_METHOD_DESCRIPTOR)); self = owner; stack_pointer[-1] = attr; - if (1) stack_pointer[0] = self; - stack_pointer += ((1) ? 1 : 0); + stack_pointer[0] = self; + stack_pointer += 1; break; } @@ -2486,8 +2945,8 @@ attr = Py_NewRef(descr); self = owner; stack_pointer[-1] = attr; - if (1) stack_pointer[0] = self; - stack_pointer += ((1) ? 1 : 0); + stack_pointer[0] = self; + stack_pointer += 1; break; } @@ -2503,7 +2962,6 @@ Py_DECREF(owner); attr = Py_NewRef(descr); stack_pointer[-1] = attr; - stack_pointer += ((0) ? 1 : 0); break; } @@ -2520,7 +2978,6 @@ Py_DECREF(owner); attr = Py_NewRef(descr); stack_pointer[-1] = attr; - stack_pointer += ((0) ? 1 : 0); break; } @@ -2549,8 +3006,8 @@ attr = Py_NewRef(descr); self = owner; stack_pointer[-1] = attr; - if (1) stack_pointer[0] = self; - stack_pointer += ((1) ? 1 : 0); + stack_pointer[0] = self; + stack_pointer += 1; break; } @@ -2662,7 +3119,6 @@ goto exit_unwind; } #endif - stack_pointer += ((0) ? 1 : 0); break; } @@ -3138,6 +3594,10 @@ /* _INSTRUMENTED_CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ + /* _CALL_FUNCTION_EX_0 is not a viable micro-op for tier 2 */ + + /* _CALL_FUNCTION_EX_1 is not a viable micro-op for tier 2 */ + /* _CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ case _MAKE_FUNCTION: { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 177bc327454f63..e3137b7bd42af7 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1004,7 +1004,6 @@ } #endif } - stack_pointer += ((0) ? 1 : 0); DISPATCH(); } @@ -1754,7 +1753,6 @@ } #endif } - stack_pointer += ((0) ? 1 : 0); DISPATCH(); } @@ -3593,8 +3591,8 @@ self = owner; } stack_pointer[-1] = attr; - if (1) stack_pointer[0] = self; - stack_pointer += ((1) ? 1 : 0); + stack_pointer[0] = self; + stack_pointer += 1; DISPATCH(); } @@ -3628,8 +3626,8 @@ self = owner; } stack_pointer[-1] = attr; - if (1) stack_pointer[0] = self; - stack_pointer += ((1) ? 1 : 0); + stack_pointer[0] = self; + stack_pointer += 1; DISPATCH(); } @@ -3675,8 +3673,8 @@ self = owner; } stack_pointer[-1] = attr; - if (1) stack_pointer[0] = self; - stack_pointer += ((1) ? 1 : 0); + stack_pointer[0] = self; + stack_pointer += 1; DISPATCH(); } @@ -3747,7 +3745,6 @@ attr = Py_NewRef(descr); } stack_pointer[-1] = attr; - stack_pointer += ((0) ? 1 : 0); DISPATCH(); } @@ -3790,7 +3787,6 @@ attr = Py_NewRef(descr); } stack_pointer[-1] = attr; - stack_pointer += ((0) ? 1 : 0); DISPATCH(); } @@ -4376,7 +4372,7 @@ Py_DECREF(self); if (attr == NULL) goto pop_3_error; stack_pointer[-3] = attr; - stack_pointer += -2 + ((0) ? 1 : 0); + stack_pointer += -2; DISPATCH(); } diff --git a/Python/optimizer.c b/Python/optimizer.c index efa19680c9b1f3..ee219a21a8bbbc 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -559,6 +559,9 @@ translate_bytecode_to_trace( for (int i = 0; i < nuops; i++) { oparg = orig_oparg; uint32_t uop = expansion->uops[i].uop; + if (_PyUop_Flags[uop] & HAS_OPARG_AND_1_FLAG) { + uop += 1 + (oparg & 1); + } uint64_t operand = 0; // Add one to account for the actual opcode/oparg pair: int offset = expansion->uops[i].offset + 1; diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index d73bc310345f41..ee8f4ddc51b7cd 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -416,7 +416,6 @@ globals_watcher_callback(PyDict_WatchEvent event, PyObject* dict, static void global_to_const(_PyUOpInstruction *inst, PyObject *obj) { - assert(inst->opcode == _LOAD_GLOBAL_MODULE || inst->opcode == _LOAD_GLOBAL_BUILTINS); assert(PyDict_CheckExact(obj)); PyDictObject *dict = (PyDictObject *)obj; assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE); @@ -528,11 +527,15 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, } break; case _LOAD_GLOBAL_BUILTINS: + case _LOAD_GLOBAL_BUILTINS_0: + case _LOAD_GLOBAL_BUILTINS_1: if (globals_checked & builtins_checked & globals_watched & builtins_watched & 1) { global_to_const(inst, builtins); } break; case _LOAD_GLOBAL_MODULE: + case _LOAD_GLOBAL_MODULE_0: + case _LOAD_GLOBAL_MODULE_1: if (globals_checked & globals_watched & 1) { global_to_const(inst, globals); } diff --git a/Python/tier2_redundancy_eliminator_cases.c.h b/Python/tier2_redundancy_eliminator_cases.c.h index a9617f51ef4615..18d2efe2b06d6e 100644 --- a/Python/tier2_redundancy_eliminator_cases.c.h +++ b/Python/tier2_redundancy_eliminator_cases.c.h @@ -619,6 +619,31 @@ break; } + case _LOAD_GLOBAL_0: { + _Py_UOpsSymType *res; + _Py_UOpsSymType *null = NULL; + res = sym_new_unknown(ctx); + if (res == NULL) goto out_of_space; + null = sym_new_null(ctx); + if (null == NULL) goto out_of_space; + stack_pointer[0] = res; + stack_pointer += 1; + break; + } + + case _LOAD_GLOBAL_1: { + _Py_UOpsSymType *res; + _Py_UOpsSymType *null = NULL; + res = sym_new_unknown(ctx); + if (res == NULL) goto out_of_space; + null = sym_new_null(ctx); + if (null == NULL) goto out_of_space; + stack_pointer[0] = res; + stack_pointer[1] = null; + stack_pointer += 2; + break; + } + case _LOAD_GLOBAL: { _Py_UOpsSymType *res; _Py_UOpsSymType *null = NULL; @@ -640,6 +665,31 @@ break; } + case _LOAD_GLOBAL_MODULE_0: { + _Py_UOpsSymType *res; + _Py_UOpsSymType *null = NULL; + res = sym_new_unknown(ctx); + if (res == NULL) goto out_of_space; + null = sym_new_null(ctx); + if (null == NULL) goto out_of_space; + stack_pointer[0] = res; + stack_pointer += 1; + break; + } + + case _LOAD_GLOBAL_MODULE_1: { + _Py_UOpsSymType *res; + _Py_UOpsSymType *null = NULL; + res = sym_new_unknown(ctx); + if (res == NULL) goto out_of_space; + null = sym_new_null(ctx); + if (null == NULL) goto out_of_space; + stack_pointer[0] = res; + stack_pointer[1] = null; + stack_pointer += 2; + break; + } + case _LOAD_GLOBAL_MODULE: { _Py_UOpsSymType *res; _Py_UOpsSymType *null = NULL; @@ -653,6 +703,31 @@ break; } + case _LOAD_GLOBAL_BUILTINS_0: { + _Py_UOpsSymType *res; + _Py_UOpsSymType *null = NULL; + res = sym_new_unknown(ctx); + if (res == NULL) goto out_of_space; + null = sym_new_null(ctx); + if (null == NULL) goto out_of_space; + stack_pointer[0] = res; + stack_pointer += 1; + break; + } + + case _LOAD_GLOBAL_BUILTINS_1: { + _Py_UOpsSymType *res; + _Py_UOpsSymType *null = NULL; + res = sym_new_unknown(ctx); + if (res == NULL) goto out_of_space; + null = sym_new_null(ctx); + if (null == NULL) goto out_of_space; + stack_pointer[0] = res; + stack_pointer[1] = null; + stack_pointer += 2; + break; + } + case _LOAD_GLOBAL_BUILTINS: { _Py_UOpsSymType *res; _Py_UOpsSymType *null = NULL; @@ -787,6 +862,10 @@ break; } + /* _INSTRUMENTED_LOAD_SUPER_ATTR_0 is not a viable micro-op for tier 2 */ + + /* _INSTRUMENTED_LOAD_SUPER_ATTR_1 is not a viable micro-op for tier 2 */ + /* _INSTRUMENTED_LOAD_SUPER_ATTR is not a viable micro-op for tier 2 */ case _LOAD_SUPER_ATTR_ATTR: { @@ -794,7 +873,7 @@ attr = sym_new_unknown(ctx); if (attr == NULL) goto out_of_space; stack_pointer[-3] = attr; - stack_pointer += -2 + ((0) ? 1 : 0); + stack_pointer += -2; break; } @@ -811,6 +890,30 @@ break; } + case _LOAD_ATTR_0: { + _Py_UOpsSymType *attr; + _Py_UOpsSymType *self_or_null = NULL; + attr = sym_new_unknown(ctx); + if (attr == NULL) goto out_of_space; + self_or_null = sym_new_unknown(ctx); + if (self_or_null == NULL) goto out_of_space; + stack_pointer[-1] = attr; + break; + } + + case _LOAD_ATTR_1: { + _Py_UOpsSymType *attr; + _Py_UOpsSymType *self_or_null = NULL; + attr = sym_new_unknown(ctx); + if (attr == NULL) goto out_of_space; + self_or_null = sym_new_unknown(ctx); + if (self_or_null == NULL) goto out_of_space; + stack_pointer[-1] = attr; + stack_pointer[0] = self_or_null; + stack_pointer += 1; + break; + } + case _LOAD_ATTR: { _Py_UOpsSymType *attr; _Py_UOpsSymType *self_or_null = NULL; @@ -832,6 +935,34 @@ break; } + case _LOAD_ATTR_INSTANCE_VALUE_0: { + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *null = NULL; + owner = stack_pointer[-1]; + uint16_t index = (uint16_t)this_instr->operand; + _LOAD_ATTR_NOT_NULL + (void)index; + (void)owner; + stack_pointer[-1] = attr; + break; + } + + case _LOAD_ATTR_INSTANCE_VALUE_1: { + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *null = NULL; + owner = stack_pointer[-1]; + uint16_t index = (uint16_t)this_instr->operand; + _LOAD_ATTR_NOT_NULL + (void)index; + (void)owner; + stack_pointer[-1] = attr; + stack_pointer[0] = null; + stack_pointer += 1; + break; + } + case _LOAD_ATTR_INSTANCE_VALUE: { _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; @@ -851,6 +982,34 @@ break; } + case _LOAD_ATTR_MODULE_0: { + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *null = NULL; + owner = stack_pointer[-1]; + uint16_t index = (uint16_t)this_instr->operand; + _LOAD_ATTR_NOT_NULL + (void)index; + (void)owner; + stack_pointer[-1] = attr; + break; + } + + case _LOAD_ATTR_MODULE_1: { + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *null = NULL; + owner = stack_pointer[-1]; + uint16_t index = (uint16_t)this_instr->operand; + _LOAD_ATTR_NOT_NULL + (void)index; + (void)owner; + stack_pointer[-1] = attr; + stack_pointer[0] = null; + stack_pointer += 1; + break; + } + case _LOAD_ATTR_MODULE: { _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; @@ -870,6 +1029,34 @@ break; } + case _LOAD_ATTR_WITH_HINT_0: { + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *null = NULL; + owner = stack_pointer[-1]; + uint16_t hint = (uint16_t)this_instr->operand; + _LOAD_ATTR_NOT_NULL + (void)hint; + (void)owner; + stack_pointer[-1] = attr; + break; + } + + case _LOAD_ATTR_WITH_HINT_1: { + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *null = NULL; + owner = stack_pointer[-1]; + uint16_t hint = (uint16_t)this_instr->operand; + _LOAD_ATTR_NOT_NULL + (void)hint; + (void)owner; + stack_pointer[-1] = attr; + stack_pointer[0] = null; + stack_pointer += 1; + break; + } + case _LOAD_ATTR_WITH_HINT: { _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; @@ -885,6 +1072,34 @@ break; } + case _LOAD_ATTR_SLOT_0: { + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *null = NULL; + owner = stack_pointer[-1]; + uint16_t index = (uint16_t)this_instr->operand; + _LOAD_ATTR_NOT_NULL + (void)index; + (void)owner; + stack_pointer[-1] = attr; + break; + } + + case _LOAD_ATTR_SLOT_1: { + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *null = NULL; + owner = stack_pointer[-1]; + uint16_t index = (uint16_t)this_instr->operand; + _LOAD_ATTR_NOT_NULL + (void)index; + (void)owner; + stack_pointer[-1] = attr; + stack_pointer[0] = null; + stack_pointer += 1; + break; + } + case _LOAD_ATTR_SLOT: { _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; @@ -904,6 +1119,34 @@ break; } + case _LOAD_ATTR_CLASS_0: { + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *null = NULL; + owner = stack_pointer[-1]; + PyObject *descr = (PyObject *)this_instr->operand; + _LOAD_ATTR_NOT_NULL + (void)descr; + (void)owner; + stack_pointer[-1] = attr; + break; + } + + case _LOAD_ATTR_CLASS_1: { + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *null = NULL; + owner = stack_pointer[-1]; + PyObject *descr = (PyObject *)this_instr->operand; + _LOAD_ATTR_NOT_NULL + (void)descr; + (void)owner; + stack_pointer[-1] = attr; + stack_pointer[0] = null; + stack_pointer += 1; + break; + } + case _LOAD_ATTR_CLASS: { _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; @@ -1229,8 +1472,8 @@ self = sym_new_unknown(ctx); if (self == NULL) goto out_of_space; stack_pointer[-1] = attr; - if (1) stack_pointer[0] = self; - stack_pointer += ((1) ? 1 : 0); + stack_pointer[0] = self; + stack_pointer += 1; break; } @@ -1242,8 +1485,8 @@ self = sym_new_unknown(ctx); if (self == NULL) goto out_of_space; stack_pointer[-1] = attr; - if (1) stack_pointer[0] = self; - stack_pointer += ((1) ? 1 : 0); + stack_pointer[0] = self; + stack_pointer += 1; break; } @@ -1252,7 +1495,6 @@ attr = sym_new_unknown(ctx); if (attr == NULL) goto out_of_space; stack_pointer[-1] = attr; - stack_pointer += ((0) ? 1 : 0); break; } @@ -1261,7 +1503,6 @@ attr = sym_new_unknown(ctx); if (attr == NULL) goto out_of_space; stack_pointer[-1] = attr; - stack_pointer += ((0) ? 1 : 0); break; } @@ -1277,8 +1518,8 @@ self = sym_new_unknown(ctx); if (self == NULL) goto out_of_space; stack_pointer[-1] = attr; - if (1) stack_pointer[0] = self; - stack_pointer += ((1) ? 1 : 0); + stack_pointer[0] = self; + stack_pointer += 1; break; } @@ -1376,7 +1617,6 @@ ctx->frame = new_frame; ctx->curr_frame_depth++; stack_pointer = new_frame->stack_pointer; - stack_pointer += ((0) ? 1 : 0); break; } @@ -1512,6 +1752,10 @@ /* _INSTRUMENTED_CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ + /* _CALL_FUNCTION_EX_0 is not a viable micro-op for tier 2 */ + + /* _CALL_FUNCTION_EX_1 is not a viable micro-op for tier 2 */ + /* _CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ case _MAKE_FUNCTION: { diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index 3497b7fcdf35d3..17f81bb3a0de11 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -1,6 +1,7 @@ from dataclasses import dataclass, field import lexer import parser +import re from typing import Optional @@ -21,9 +22,9 @@ class Properties: uses_co_names: bool uses_locals: bool has_free: bool - pure: bool passthrough: bool + oparg_and_1: bool = False def dump(self, indent: str) -> None: print(indent, end="") @@ -268,17 +269,19 @@ def override_error( ) -def convert_stack_item(item: parser.StackEffect) -> StackItem: +def convert_stack_item(item: parser.StackEffect, replace_op_arg_1: str | None) -> StackItem: + cond = item.cond + if replace_op_arg_1 and OPARG_AND_1.match(item.cond): + cond = replace_op_arg_1 return StackItem( - item.name, item.type, item.cond, (item.size or "1") + item.name, item.type, cond, (item.size or "1") ) - -def analyze_stack(op: parser.InstDef) -> StackEffect: +def analyze_stack(op: parser.InstDef, replace_op_arg_1: str | None = None) -> StackEffect: inputs: list[StackItem] = [ - convert_stack_item(i) for i in op.inputs if isinstance(i, parser.StackEffect) + convert_stack_item(i, replace_op_arg_1) for i in op.inputs if isinstance(i, parser.StackEffect) ] - outputs: list[StackItem] = [convert_stack_item(i) for i in op.outputs] + outputs: list[StackItem] = [convert_stack_item(i, replace_op_arg_1) for i in op.outputs] for input, output in zip(inputs, outputs): if input.name == output.name: input.peek = output.peek = True @@ -441,6 +444,22 @@ def stack_effect_only_peeks(instr: parser.InstDef) -> bool: for s, other in zip(stack_inputs, instr.outputs) ) +OPARG_AND_1 = re.compile("\(*oparg *& *1") + +def effect_depends_on_oparg_1(op: parser.InstDef) -> bool: + for effect in op.inputs: + if isinstance(effect, parser.CacheEffect): + continue + if not effect.cond: + continue + if OPARG_AND_1.match(effect.cond): + return True + for effect in op.outputs: + if not effect.cond: + continue + if OPARG_AND_1.match(effect.cond): + return True + return False def compute_properties(op: parser.InstDef) -> Properties: has_free = ( @@ -473,8 +492,8 @@ def compute_properties(op: parser.InstDef) -> Properties: ) -def make_uop(name: str, op: parser.InstDef, inputs: list[parser.InputEffect]) -> Uop: - return Uop( +def make_uop(name: str, op: parser.InstDef, inputs: list[parser.InputEffect], uops: dict[str, Uop]) -> Uop: + result = Uop( name=name, context=op.context, annotations=op.annotations, @@ -483,6 +502,20 @@ def make_uop(name: str, op: parser.InstDef, inputs: list[parser.InputEffect]) -> body=op.block.tokens, properties=compute_properties(op), ) + if effect_depends_on_oparg_1(op): + result.properties.oparg_and_1 = True + for bit in ("0", "1"): + name_x = name + "_" + bit + uops[name_x] = Uop( + name=name_x, + context=op.context, + annotations=op.annotations, + stack=analyze_stack(op, bit), + caches=analyze_caches(inputs), + body=op.block.tokens, + properties=compute_properties(op), + ) + return result def add_op(op: parser.InstDef, uops: dict[str, Uop]) -> None: @@ -492,7 +525,7 @@ def add_op(op: parser.InstDef, uops: dict[str, Uop]) -> None: raise override_error( op.name, op.context, uops[op.name].context, op.tokens[0] ) - uops[op.name] = make_uop(op.name, op, op.inputs) + uops[op.name] = make_uop(op.name, op, op.inputs, uops) def add_instruction( @@ -519,7 +552,7 @@ def desugar_inst( uop_index = len(parts) # Place holder for the uop. parts.append(Skip(0)) - uop = make_uop("_" + inst.name, inst, op_inputs) + uop = make_uop("_" + inst.name, inst, op_inputs, uops) uop.implicitly_created = True uops[inst.name] = uop if uop_index < 0: diff --git a/Tools/cases_generator/generators_common.py b/Tools/cases_generator/generators_common.py index 2fc2ab115321cf..d48f90dd385cd9 100644 --- a/Tools/cases_generator/generators_common.py +++ b/Tools/cases_generator/generators_common.py @@ -119,7 +119,10 @@ def replace_decrefs( out.emit(f"Py_DECREF({var.name}[_i]);\n") out.emit("}\n") elif var.condition: - out.emit(f"Py_XDECREF({var.name});\n") + if var.condition == "1": + out.emit(f"Py_DECREF({var.name});\n") + elif var.condition != "0": + out.emit(f"Py_XDECREF({var.name});\n") else: out.emit(f"Py_DECREF({var.name});\n") @@ -213,6 +216,8 @@ def cflags(p: Properties) -> str: flags.append("HAS_PURE_FLAG") if p.passthrough: flags.append("HAS_PASSTHROUGH_FLAG") + if p.oparg_and_1: + flags.append("HAS_OPARG_AND_1_FLAG") if flags: return " | ".join(flags) else: diff --git a/Tools/cases_generator/opcode_metadata_generator.py b/Tools/cases_generator/opcode_metadata_generator.py index 3e9fa3e26daa53..461fb2514a408c 100644 --- a/Tools/cases_generator/opcode_metadata_generator.py +++ b/Tools/cases_generator/opcode_metadata_generator.py @@ -52,6 +52,7 @@ "ESCAPES", "PURE", "PASSTHROUGH", + "OPARG_AND_1", ] diff --git a/Tools/cases_generator/stack.py b/Tools/cases_generator/stack.py index 97a301142d59c7..5aecac39aef5e2 100644 --- a/Tools/cases_generator/stack.py +++ b/Tools/cases_generator/stack.py @@ -23,8 +23,12 @@ def maybe_parenthesize(sym: str) -> str: def var_size(var: StackItem) -> str: if var.condition: - # Special case simplification - if var.condition == "oparg & 1" and var.size == "1": + # Special case simplifications + if var.condition == "0": + return "0" + elif var.condition == "1": + return var.size + elif var.condition == "oparg & 1" and var.size == "1": return f"({var.condition})" else: return f"(({var.condition}) ? {var.size} : 0)" @@ -154,7 +158,12 @@ def pop(self, var: StackItem) -> str: f"{var.name} = {cast}{indirect}stack_pointer[{self.base_offset.to_c()}];" ) if var.condition: - return f"if ({var.condition}) {{ {assign} }}\n" + if var.condition == "1": + return f"{assign}\n" + elif var.condition == "0": + return "" + else: + return f"if ({var.condition}) {{ {assign} }}\n" return f"{assign}\n" def push(self, var: StackItem) -> str: @@ -175,7 +184,10 @@ def flush(self, out: CWriter, cast_type: str = "PyObject *") -> None: cast = f"({cast_type})" if var.type else "" if var.name not in UNUSED and not var.is_array(): if var.condition: - out.emit(f"if ({var.condition}) ") + if var.condition == "0": + continue + elif var.condition != "1": + out.emit(f"if ({var.condition}) ") out.emit( f"stack_pointer[{self.base_offset.to_c()}] = {cast}{var.name};\n" ) diff --git a/Tools/cases_generator/tier2_generator.py b/Tools/cases_generator/tier2_generator.py index 7897b89b2752a7..a69899eec811ca 100644 --- a/Tools/cases_generator/tier2_generator.py +++ b/Tools/cases_generator/tier2_generator.py @@ -98,9 +98,30 @@ def tier2_replace_deopt( out.emit(") goto deoptimize;\n") +def tier2_replace_oparg( + out: CWriter, + tkn: Token, + tkn_iter: Iterator[Token], + uop: Uop, + unused: Stack, + inst: Instruction | None, +) -> None: + if not uop.name.endswith("_0") and not uop.name.endswith("_1"): + out.emit(tkn) + return + amp = next(tkn_iter) + if amp.text != "&": + out.emit(tkn) + out.emit(amp) + return + one = next(tkn_iter) + assert(one.text == "1") + out.emit_at(uop.name[-1], tkn) + TIER2_REPLACEMENT_FUNCTIONS = REPLACEMENT_FUNCTIONS.copy() TIER2_REPLACEMENT_FUNCTIONS["ERROR_IF"] = tier2_replace_error TIER2_REPLACEMENT_FUNCTIONS["DEOPT_IF"] = tier2_replace_deopt +TIER2_REPLACEMENT_FUNCTIONS["oparg"] = tier2_replace_oparg def write_uop(uop: Uop, out: CWriter, stack: Stack) -> None: diff --git a/Tools/cases_generator/uop_id_generator.py b/Tools/cases_generator/uop_id_generator.py index 633249f1c6b1fe..b7aa2351726408 100644 --- a/Tools/cases_generator/uop_id_generator.py +++ b/Tools/cases_generator/uop_id_generator.py @@ -38,15 +38,17 @@ def generate_uop_ids( next_id += 1 PRE_DEFINED = {"_EXIT_TRACE", "_SET_IP"} - for uop in analysis.uops.values(): - if uop.name in PRE_DEFINED: + uops = [(uop.name, uop) for uop in analysis.uops.values()] + # Sort so that _BASE comes immediately before _BASE_0, etc. + for name, uop in sorted(uops): + if name in PRE_DEFINED: continue if uop.properties.tier_one_only: continue if uop.implicitly_created and not distinct_namespace: - out.emit(f"#define {uop.name} {uop.name[1:]}\n") + out.emit(f"#define {name} {name[1:]}\n") else: - out.emit(f"#define {uop.name} {next_id}\n") + out.emit(f"#define {name} {next_id}\n") next_id += 1 out.emit(f"#define MAX_UOP_ID {next_id-1}\n") From d8797782e1e092b04655dac2f5e2738c045ad63f Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 14 Feb 2024 21:08:25 +0000 Subject: [PATCH 2/5] Don't generate C code for split uops --- Python/executor_cases.c.h | 239 ++--------------------- Tools/cases_generator/tier2_generator.py | 3 + 2 files changed, 14 insertions(+), 228 deletions(-) diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 70d91ffe7d4b76..65551a838b43cd 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1174,49 +1174,7 @@ break; } - case _LOAD_GLOBAL: { - PyObject *res; - PyObject *null = NULL; - oparg = CURRENT_OPARG(); - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); - if (PyDict_CheckExact(GLOBALS()) - && PyDict_CheckExact(BUILTINS())) - { - res = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(), - (PyDictObject *)BUILTINS(), - name); - if (res == NULL) { - if (!_PyErr_Occurred(tstate)) { - /* _PyDict_LoadGlobal() returns NULL without raising - * an exception if the key doesn't exist */ - _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } - if (true) goto error_tier_two; - } - Py_INCREF(res); - } - else { - /* Slow-path if globals or builtins is not a dict */ - /* namespace 1: globals */ - if (PyMapping_GetOptionalItem(GLOBALS(), name, &res) < 0) goto error_tier_two; - if (res == NULL) { - /* namespace 2: builtins */ - if (PyMapping_GetOptionalItem(BUILTINS(), name, &res) < 0) goto error_tier_two; - if (res == NULL) { - _PyEval_FormatExcCheckArg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - if (true) goto error_tier_two; - } - } - } - null = NULL; - stack_pointer[0] = res; - if (oparg & 1) stack_pointer[1] = null; - stack_pointer += 1 + (oparg & 1); - break; - } + /* _LOAD_GLOBAL is split on (oparg & 1) */ case _GUARD_GLOBALS_VERSION: { uint16_t version = (uint16_t)CURRENT_OPERAND(); @@ -1271,23 +1229,7 @@ break; } - case _LOAD_GLOBAL_MODULE: { - PyObject *res; - PyObject *null = NULL; - oparg = CURRENT_OPARG(); - uint16_t index = (uint16_t)CURRENT_OPERAND(); - PyDictObject *dict = (PyDictObject *)GLOBALS(); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); - res = entries[index].me_value; - if (res == NULL) goto deoptimize; - Py_INCREF(res); - STAT_INC(LOAD_GLOBAL, hit); - null = NULL; - stack_pointer[0] = res; - if (oparg & 1) stack_pointer[1] = null; - stack_pointer += 1 + (oparg & 1); - break; - } + /* _LOAD_GLOBAL_MODULE is split on (oparg & 1) */ case _LOAD_GLOBAL_BUILTINS_0: { PyObject *res; @@ -1324,23 +1266,7 @@ break; } - case _LOAD_GLOBAL_BUILTINS: { - PyObject *res; - PyObject *null = NULL; - oparg = CURRENT_OPARG(); - uint16_t index = (uint16_t)CURRENT_OPERAND(); - PyDictObject *bdict = (PyDictObject *)BUILTINS(); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys); - res = entries[index].me_value; - if (res == NULL) goto deoptimize; - Py_INCREF(res); - STAT_INC(LOAD_GLOBAL, hit); - null = NULL; - stack_pointer[0] = res; - if (oparg & 1) stack_pointer[1] = null; - stack_pointer += 1 + (oparg & 1); - break; - } + /* _LOAD_GLOBAL_BUILTINS is split on (oparg & 1) */ case _DELETE_FAST: { oparg = CURRENT_OPARG(); @@ -1673,7 +1599,7 @@ /* _INSTRUMENTED_LOAD_SUPER_ATTR_1 is not a viable micro-op for tier 2 */ - /* _INSTRUMENTED_LOAD_SUPER_ATTR is not a viable micro-op for tier 2 */ + /* _INSTRUMENTED_LOAD_SUPER_ATTR is split on (oparg & 1) */ case _LOAD_SUPER_ATTR_ATTR: { PyObject *self; @@ -1818,47 +1744,7 @@ break; } - case _LOAD_ATTR: { - PyObject *owner; - PyObject *attr; - PyObject *self_or_null = NULL; - oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); - if (oparg & 1) { - /* Designed to work in tandem with CALL, pushes two values. */ - attr = NULL; - if (_PyObject_GetMethod(owner, name, &attr)) { - /* We can bypass temporary bound method object. - meth is unbound method and obj is self. - meth | self | arg1 | ... | argN - */ - assert(attr != NULL); // No errors on this branch - self_or_null = owner; // Transfer ownership - } - else { - /* meth is not an unbound method (but a regular attr, or - something was returned by a descriptor protocol). Set - the second element of the stack to NULL, to signal - CALL that it's not a method call. - meth | NULL | arg1 | ... | argN - */ - Py_DECREF(owner); - if (attr == NULL) goto pop_1_error_tier_two; - self_or_null = NULL; - } - } - else { - /* Classic, pushes one value. */ - attr = PyObject_GetAttr(owner, name); - Py_DECREF(owner); - if (attr == NULL) goto pop_1_error_tier_two; - } - stack_pointer[-1] = attr; - if (oparg & 1) stack_pointer[0] = self_or_null; - stack_pointer += (oparg & 1); - break; - } + /* _LOAD_ATTR is split on (oparg & 1) */ case _GUARD_TYPE_VERSION: { PyObject *owner; @@ -1918,25 +1804,7 @@ break; } - case _LOAD_ATTR_INSTANCE_VALUE: { - PyObject *owner; - PyObject *attr; - PyObject *null = NULL; - oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - uint16_t index = (uint16_t)CURRENT_OPERAND(); - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); - attr = _PyDictOrValues_GetValues(dorv)->values[index]; - if (attr == NULL) goto deoptimize; - STAT_INC(LOAD_ATTR, hit); - Py_INCREF(attr); - null = NULL; - Py_DECREF(owner); - stack_pointer[-1] = attr; - if (oparg & 1) stack_pointer[0] = null; - stack_pointer += (oparg & 1); - break; - } + /* _LOAD_ATTR_INSTANCE_VALUE is split on (oparg & 1) */ case _CHECK_ATTR_MODULE: { PyObject *owner; @@ -1993,28 +1861,7 @@ break; } - case _LOAD_ATTR_MODULE: { - PyObject *owner; - PyObject *attr; - PyObject *null = NULL; - oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - uint16_t index = (uint16_t)CURRENT_OPERAND(); - PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; - assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE); - assert(index < dict->ma_keys->dk_nentries); - PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + index; - attr = ep->me_value; - if (attr == NULL) goto deoptimize; - STAT_INC(LOAD_ATTR, hit); - Py_INCREF(attr); - null = NULL; - Py_DECREF(owner); - stack_pointer[-1] = attr; - if (oparg & 1) stack_pointer[0] = null; - stack_pointer += (oparg & 1); - break; - } + /* _LOAD_ATTR_MODULE is split on (oparg & 1) */ case _CHECK_ATTR_WITH_HINT: { PyObject *owner; @@ -2090,37 +1937,7 @@ break; } - case _LOAD_ATTR_WITH_HINT: { - PyObject *owner; - PyObject *attr; - PyObject *null = NULL; - oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - uint16_t hint = (uint16_t)CURRENT_OPERAND(); - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); - PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); - if (hint >= (size_t)dict->ma_keys->dk_nentries) goto deoptimize; - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); - if (DK_IS_UNICODE(dict->ma_keys)) { - PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; - if (ep->me_key != name) goto deoptimize; - attr = ep->me_value; - } - else { - PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint; - if (ep->me_key != name) goto deoptimize; - attr = ep->me_value; - } - if (attr == NULL) goto deoptimize; - STAT_INC(LOAD_ATTR, hit); - Py_INCREF(attr); - null = NULL; - Py_DECREF(owner); - stack_pointer[-1] = attr; - if (oparg & 1) stack_pointer[0] = null; - stack_pointer += (oparg & 1); - break; - } + /* _LOAD_ATTR_WITH_HINT is split on (oparg & 1) */ case _LOAD_ATTR_SLOT_0: { PyObject *owner; @@ -2160,25 +1977,7 @@ break; } - case _LOAD_ATTR_SLOT: { - PyObject *owner; - PyObject *attr; - PyObject *null = NULL; - oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - uint16_t index = (uint16_t)CURRENT_OPERAND(); - char *addr = (char *)owner + index; - attr = *(PyObject **)addr; - if (attr == NULL) goto deoptimize; - STAT_INC(LOAD_ATTR, hit); - Py_INCREF(attr); - null = NULL; - Py_DECREF(owner); - stack_pointer[-1] = attr; - if (oparg & 1) stack_pointer[0] = null; - stack_pointer += (oparg & 1); - break; - } + /* _LOAD_ATTR_SLOT is split on (oparg & 1) */ case _CHECK_ATTR_CLASS: { PyObject *owner; @@ -2224,23 +2023,7 @@ break; } - case _LOAD_ATTR_CLASS: { - PyObject *owner; - PyObject *attr; - PyObject *null = NULL; - oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - PyObject *descr = (PyObject *)CURRENT_OPERAND(); - STAT_INC(LOAD_ATTR, hit); - assert(descr != NULL); - attr = Py_NewRef(descr); - null = NULL; - Py_DECREF(owner); - stack_pointer[-1] = attr; - if (oparg & 1) stack_pointer[0] = null; - stack_pointer += (oparg & 1); - break; - } + /* _LOAD_ATTR_CLASS is split on (oparg & 1) */ /* _LOAD_ATTR_PROPERTY is not a viable micro-op for tier 2 */ @@ -3598,7 +3381,7 @@ /* _CALL_FUNCTION_EX_1 is not a viable micro-op for tier 2 */ - /* _CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ + /* _CALL_FUNCTION_EX is split on (oparg & 1) */ case _MAKE_FUNCTION: { PyObject *codeobj; diff --git a/Tools/cases_generator/tier2_generator.py b/Tools/cases_generator/tier2_generator.py index a69899eec811ca..0093a1b12be8b9 100644 --- a/Tools/cases_generator/tier2_generator.py +++ b/Tools/cases_generator/tier2_generator.py @@ -170,6 +170,9 @@ def generate_tier2( for name, uop in analysis.uops.items(): if uop.properties.tier_one_only: continue + if uop.properties.oparg_and_1: + out.emit(f"/* {uop.name} is split on (oparg & 1) */\n\n") + continue if uop.is_super(): continue if not uop.is_viable(): From 472a3d6baf3e8c0bfaf0d0ae274171d1e4d5eee8 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 15 Feb 2024 01:26:54 +0000 Subject: [PATCH 3/5] Add replicate annotation --- Include/internal/pycore_uop_ids.h | 205 +++---- Include/internal/pycore_uop_metadata.h | 97 ++-- Lib/test/test_capi/test_opt.py | 2 +- Python/bytecodes.c | 16 +- Python/ceval.c | 2 +- Python/executor_cases.c.h | 542 +++++++++++------- Python/optimizer.c | 18 +- Python/optimizer_analysis.c | 6 +- Python/tier2_redundancy_eliminator_cases.c.h | 223 +------ Tools/cases_generator/analyzer.py | 36 +- Tools/cases_generator/lexer.py | 2 + Tools/cases_generator/parsing.py | 8 +- .../tier2_abstract_generator.py | 2 + Tools/cases_generator/tier2_generator.py | 4 + Tools/cases_generator/uop_id_generator.py | 2 +- .../cases_generator/uop_metadata_generator.py | 7 + 16 files changed, 600 insertions(+), 572 deletions(-) diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 583f6129c9d3d7..572e7d3fdc00f2 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -42,8 +42,6 @@ extern "C" { #define _CALL_BUILTIN_FAST_WITH_KEYWORDS CALL_BUILTIN_FAST_WITH_KEYWORDS #define _CALL_BUILTIN_O CALL_BUILTIN_O #define _CALL_FUNCTION_EX CALL_FUNCTION_EX -#define _CALL_FUNCTION_EX_0 312 -#define _CALL_FUNCTION_EX_1 313 #define _CALL_INTRINSIC_1 CALL_INTRINSIC_1 #define _CALL_INTRINSIC_2 CALL_INTRINSIC_2 #define _CALL_ISINSTANCE CALL_ISINSTANCE @@ -57,22 +55,22 @@ extern "C" { #define _CALL_STR_1 CALL_STR_1 #define _CALL_TUPLE_1 CALL_TUPLE_1 #define _CALL_TYPE_1 CALL_TYPE_1 -#define _CHECK_ATTR_CLASS 314 -#define _CHECK_ATTR_METHOD_LAZY_DICT 315 -#define _CHECK_ATTR_MODULE 316 -#define _CHECK_ATTR_WITH_HINT 317 -#define _CHECK_BUILTINS 318 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 319 +#define _CHECK_ATTR_CLASS 312 +#define _CHECK_ATTR_METHOD_LAZY_DICT 313 +#define _CHECK_ATTR_MODULE 314 +#define _CHECK_ATTR_WITH_HINT 315 +#define _CHECK_BUILTINS 316 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 317 #define _CHECK_EG_MATCH CHECK_EG_MATCH #define _CHECK_EXC_MATCH CHECK_EXC_MATCH -#define _CHECK_FUNCTION_EXACT_ARGS 320 -#define _CHECK_GLOBALS 321 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES 322 -#define _CHECK_PEP_523 323 -#define _CHECK_STACK_SPACE 324 -#define _CHECK_VALIDITY 325 -#define _CHECK_VALIDITY_AND_SET_IP 326 -#define _COMPARE_OP 327 +#define _CHECK_FUNCTION_EXACT_ARGS 318 +#define _CHECK_GLOBALS 319 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES 320 +#define _CHECK_PEP_523 321 +#define _CHECK_STACK_SPACE 322 +#define _CHECK_VALIDITY 323 +#define _CHECK_VALIDITY_AND_SET_IP 324 +#define _COMPARE_OP 325 #define _COMPARE_OP_FLOAT COMPARE_OP_FLOAT #define _COMPARE_OP_INT COMPARE_OP_INT #define _COMPARE_OP_STR COMPARE_OP_STR @@ -92,33 +90,38 @@ extern "C" { #define _EXIT_INIT_CHECK EXIT_INIT_CHECK #define _FORMAT_SIMPLE FORMAT_SIMPLE #define _FORMAT_WITH_SPEC FORMAT_WITH_SPEC -#define _FOR_ITER 328 +#define _FOR_ITER 326 #define _FOR_ITER_GEN FOR_ITER_GEN -#define _FOR_ITER_TIER_TWO 329 +#define _FOR_ITER_TIER_TWO 327 #define _GET_AITER GET_AITER #define _GET_ANEXT GET_ANEXT #define _GET_AWAITABLE GET_AWAITABLE #define _GET_ITER GET_ITER #define _GET_LEN GET_LEN #define _GET_YIELD_FROM_ITER GET_YIELD_FROM_ITER -#define _GUARD_BOTH_FLOAT 330 -#define _GUARD_BOTH_INT 331 -#define _GUARD_BOTH_UNICODE 332 -#define _GUARD_BUILTINS_VERSION 333 -#define _GUARD_DORV_VALUES 334 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 335 -#define _GUARD_GLOBALS_VERSION 336 -#define _GUARD_IS_FALSE_POP 337 -#define _GUARD_IS_NONE_POP 338 -#define _GUARD_IS_NOT_NONE_POP 339 -#define _GUARD_IS_TRUE_POP 340 -#define _GUARD_KEYS_VERSION 341 -#define _GUARD_NOT_EXHAUSTED_LIST 342 -#define _GUARD_NOT_EXHAUSTED_RANGE 343 -#define _GUARD_NOT_EXHAUSTED_TUPLE 344 -#define _GUARD_TYPE_VERSION 345 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 346 -#define _INIT_CALL_PY_EXACT_ARGS 347 +#define _GUARD_BOTH_FLOAT 328 +#define _GUARD_BOTH_INT 329 +#define _GUARD_BOTH_UNICODE 330 +#define _GUARD_BUILTINS_VERSION 331 +#define _GUARD_DORV_VALUES 332 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 333 +#define _GUARD_GLOBALS_VERSION 334 +#define _GUARD_IS_FALSE_POP 335 +#define _GUARD_IS_NONE_POP 336 +#define _GUARD_IS_NOT_NONE_POP 337 +#define _GUARD_IS_TRUE_POP 338 +#define _GUARD_KEYS_VERSION 339 +#define _GUARD_NOT_EXHAUSTED_LIST 340 +#define _GUARD_NOT_EXHAUSTED_RANGE 341 +#define _GUARD_NOT_EXHAUSTED_TUPLE 342 +#define _GUARD_TYPE_VERSION 343 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 344 +#define _INIT_CALL_PY_EXACT_ARGS 345 +#define _INIT_CALL_PY_EXACT_ARGS_0 346 +#define _INIT_CALL_PY_EXACT_ARGS_1 347 +#define _INIT_CALL_PY_EXACT_ARGS_2 348 +#define _INIT_CALL_PY_EXACT_ARGS_3 349 +#define _INIT_CALL_PY_EXACT_ARGS_4 350 #define _INSTRUMENTED_CALL INSTRUMENTED_CALL #define _INSTRUMENTED_CALL_FUNCTION_EX INSTRUMENTED_CALL_FUNCTION_EX #define _INSTRUMENTED_CALL_KW INSTRUMENTED_CALL_KW @@ -127,8 +130,6 @@ extern "C" { #define _INSTRUMENTED_JUMP_BACKWARD INSTRUMENTED_JUMP_BACKWARD #define _INSTRUMENTED_JUMP_FORWARD INSTRUMENTED_JUMP_FORWARD #define _INSTRUMENTED_LOAD_SUPER_ATTR INSTRUMENTED_LOAD_SUPER_ATTR -#define _INSTRUMENTED_LOAD_SUPER_ATTR_0 348 -#define _INSTRUMENTED_LOAD_SUPER_ATTR_1 349 #define _INSTRUMENTED_POP_JUMP_IF_FALSE INSTRUMENTED_POP_JUMP_IF_FALSE #define _INSTRUMENTED_POP_JUMP_IF_NONE INSTRUMENTED_POP_JUMP_IF_NONE #define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE INSTRUMENTED_POP_JUMP_IF_NOT_NONE @@ -137,70 +138,66 @@ extern "C" { #define _INSTRUMENTED_RETURN_CONST INSTRUMENTED_RETURN_CONST #define _INSTRUMENTED_RETURN_VALUE INSTRUMENTED_RETURN_VALUE #define _INSTRUMENTED_YIELD_VALUE INSTRUMENTED_YIELD_VALUE -#define _INTERNAL_INCREMENT_OPT_COUNTER 350 -#define _IS_NONE 351 +#define _INTERNAL_INCREMENT_OPT_COUNTER 351 +#define _IS_NONE 352 #define _IS_OP IS_OP -#define _ITER_CHECK_LIST 352 -#define _ITER_CHECK_RANGE 353 -#define _ITER_CHECK_TUPLE 354 -#define _ITER_JUMP_LIST 355 -#define _ITER_JUMP_RANGE 356 -#define _ITER_JUMP_TUPLE 357 -#define _ITER_NEXT_LIST 358 -#define _ITER_NEXT_RANGE 359 -#define _ITER_NEXT_TUPLE 360 +#define _ITER_CHECK_LIST 353 +#define _ITER_CHECK_RANGE 354 +#define _ITER_CHECK_TUPLE 355 +#define _ITER_JUMP_LIST 356 +#define _ITER_JUMP_RANGE 357 +#define _ITER_JUMP_TUPLE 358 +#define _ITER_NEXT_LIST 359 +#define _ITER_NEXT_RANGE 360 +#define _ITER_NEXT_TUPLE 361 #define _JUMP_BACKWARD JUMP_BACKWARD -#define _JUMP_TO_TOP 361 +#define _JUMP_TO_TOP 362 #define _LIST_APPEND LIST_APPEND #define _LIST_EXTEND LIST_EXTEND #define _LOAD_ASSERTION_ERROR LOAD_ASSERTION_ERROR -#define _LOAD_ATTR 362 -#define _LOAD_ATTR_0 363 -#define _LOAD_ATTR_1 364 -#define _LOAD_ATTR_CLASS 365 -#define _LOAD_ATTR_CLASS_0 366 -#define _LOAD_ATTR_CLASS_1 367 +#define _LOAD_ATTR 363 +#define _LOAD_ATTR_CLASS 364 +#define _LOAD_ATTR_CLASS_0 365 +#define _LOAD_ATTR_CLASS_1 366 #define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN -#define _LOAD_ATTR_INSTANCE_VALUE 368 -#define _LOAD_ATTR_INSTANCE_VALUE_0 369 -#define _LOAD_ATTR_INSTANCE_VALUE_1 370 -#define _LOAD_ATTR_METHOD_LAZY_DICT 371 -#define _LOAD_ATTR_METHOD_NO_DICT 372 -#define _LOAD_ATTR_METHOD_WITH_VALUES 373 -#define _LOAD_ATTR_MODULE 374 -#define _LOAD_ATTR_MODULE_0 375 -#define _LOAD_ATTR_MODULE_1 376 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 377 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 378 +#define _LOAD_ATTR_INSTANCE_VALUE 367 +#define _LOAD_ATTR_INSTANCE_VALUE_0 368 +#define _LOAD_ATTR_INSTANCE_VALUE_1 369 +#define _LOAD_ATTR_METHOD_LAZY_DICT 370 +#define _LOAD_ATTR_METHOD_NO_DICT 371 +#define _LOAD_ATTR_METHOD_WITH_VALUES 372 +#define _LOAD_ATTR_MODULE 373 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 374 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 375 #define _LOAD_ATTR_PROPERTY LOAD_ATTR_PROPERTY -#define _LOAD_ATTR_SLOT 379 -#define _LOAD_ATTR_SLOT_0 380 -#define _LOAD_ATTR_SLOT_1 381 -#define _LOAD_ATTR_WITH_HINT 382 -#define _LOAD_ATTR_WITH_HINT_0 383 -#define _LOAD_ATTR_WITH_HINT_1 384 +#define _LOAD_ATTR_SLOT 376 +#define _LOAD_ATTR_SLOT_0 377 +#define _LOAD_ATTR_SLOT_1 378 +#define _LOAD_ATTR_WITH_HINT 379 #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS #define _LOAD_CONST LOAD_CONST -#define _LOAD_CONST_INLINE 385 -#define _LOAD_CONST_INLINE_BORROW 386 -#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 387 -#define _LOAD_CONST_INLINE_WITH_NULL 388 +#define _LOAD_CONST_INLINE 380 +#define _LOAD_CONST_INLINE_BORROW 381 +#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 382 +#define _LOAD_CONST_INLINE_WITH_NULL 383 #define _LOAD_DEREF LOAD_DEREF -#define _LOAD_FAST LOAD_FAST +#define _LOAD_FAST 384 +#define _LOAD_FAST_0 385 +#define _LOAD_FAST_1 386 +#define _LOAD_FAST_2 387 +#define _LOAD_FAST_3 388 +#define _LOAD_FAST_4 389 +#define _LOAD_FAST_5 390 +#define _LOAD_FAST_6 391 +#define _LOAD_FAST_7 392 #define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR #define _LOAD_FAST_CHECK LOAD_FAST_CHECK #define _LOAD_FAST_LOAD_FAST LOAD_FAST_LOAD_FAST #define _LOAD_FROM_DICT_OR_DEREF LOAD_FROM_DICT_OR_DEREF #define _LOAD_FROM_DICT_OR_GLOBALS LOAD_FROM_DICT_OR_GLOBALS -#define _LOAD_GLOBAL 389 -#define _LOAD_GLOBAL_0 390 -#define _LOAD_GLOBAL_1 391 -#define _LOAD_GLOBAL_BUILTINS 392 -#define _LOAD_GLOBAL_BUILTINS_0 393 -#define _LOAD_GLOBAL_BUILTINS_1 394 +#define _LOAD_GLOBAL 393 +#define _LOAD_GLOBAL_BUILTINS 394 #define _LOAD_GLOBAL_MODULE 395 -#define _LOAD_GLOBAL_MODULE_0 396 -#define _LOAD_GLOBAL_MODULE_1 397 #define _LOAD_LOCALS LOAD_LOCALS #define _LOAD_NAME LOAD_NAME #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR @@ -214,37 +211,45 @@ extern "C" { #define _MATCH_SEQUENCE MATCH_SEQUENCE #define _NOP NOP #define _POP_EXCEPT POP_EXCEPT -#define _POP_FRAME 398 -#define _POP_JUMP_IF_FALSE 399 -#define _POP_JUMP_IF_TRUE 400 +#define _POP_FRAME 396 +#define _POP_JUMP_IF_FALSE 397 +#define _POP_JUMP_IF_TRUE 398 #define _POP_TOP POP_TOP #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _PUSH_FRAME 401 +#define _PUSH_FRAME 399 #define _PUSH_NULL PUSH_NULL #define _RESUME_CHECK RESUME_CHECK -#define _SAVE_RETURN_OFFSET 402 -#define _SEND 403 +#define _SAVE_RETURN_OFFSET 400 +#define _SEND 401 #define _SEND_GEN SEND_GEN #define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS #define _SET_ADD SET_ADD #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE #define _SET_UPDATE SET_UPDATE -#define _STORE_ATTR 404 -#define _STORE_ATTR_INSTANCE_VALUE 405 -#define _STORE_ATTR_SLOT 406 +#define _STORE_ATTR 402 +#define _STORE_ATTR_INSTANCE_VALUE 403 +#define _STORE_ATTR_SLOT 404 #define _STORE_ATTR_WITH_HINT STORE_ATTR_WITH_HINT #define _STORE_DEREF STORE_DEREF -#define _STORE_FAST STORE_FAST +#define _STORE_FAST 405 +#define _STORE_FAST_0 406 +#define _STORE_FAST_1 407 +#define _STORE_FAST_2 408 +#define _STORE_FAST_3 409 +#define _STORE_FAST_4 410 +#define _STORE_FAST_5 411 +#define _STORE_FAST_6 412 +#define _STORE_FAST_7 413 #define _STORE_FAST_LOAD_FAST STORE_FAST_LOAD_FAST #define _STORE_FAST_STORE_FAST STORE_FAST_STORE_FAST #define _STORE_GLOBAL STORE_GLOBAL #define _STORE_NAME STORE_NAME #define _STORE_SLICE STORE_SLICE -#define _STORE_SUBSCR 407 +#define _STORE_SUBSCR 414 #define _STORE_SUBSCR_DICT STORE_SUBSCR_DICT #define _STORE_SUBSCR_LIST_INT STORE_SUBSCR_LIST_INT #define _SWAP SWAP -#define _TO_BOOL 408 +#define _TO_BOOL 415 #define _TO_BOOL_ALWAYS_TRUE TO_BOOL_ALWAYS_TRUE #define _TO_BOOL_BOOL TO_BOOL_BOOL #define _TO_BOOL_INT TO_BOOL_INT @@ -255,12 +260,12 @@ extern "C" { #define _UNARY_NEGATIVE UNARY_NEGATIVE #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 409 +#define _UNPACK_SEQUENCE 416 #define _UNPACK_SEQUENCE_LIST UNPACK_SEQUENCE_LIST #define _UNPACK_SEQUENCE_TUPLE UNPACK_SEQUENCE_TUPLE #define _UNPACK_SEQUENCE_TWO_TUPLE UNPACK_SEQUENCE_TWO_TUPLE #define _WITH_EXCEPT_START WITH_EXCEPT_START -#define MAX_UOP_ID 409 +#define MAX_UOP_ID 416 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index a305074cbed914..ccd0d53588f7dc 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -12,6 +12,7 @@ extern "C" { #include #include "pycore_uop_ids.h" extern const uint16_t _PyUop_Flags[MAX_UOP_ID+1]; +extern const uint8_t _PyUop_Replication[MAX_UOP_ID+1]; extern const char * const _PyOpcode_uop_name[MAX_UOP_ID+1]; #ifdef NEED_OPCODE_METADATA @@ -19,10 +20,26 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_NOP] = HAS_PURE_FLAG, [_RESUME_CHECK] = HAS_DEOPT_FLAG, [_LOAD_FAST_CHECK] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ERROR_FLAG, + [_LOAD_FAST_0] = HAS_LOCAL_FLAG | HAS_PURE_FLAG, + [_LOAD_FAST_1] = HAS_LOCAL_FLAG | HAS_PURE_FLAG, + [_LOAD_FAST_2] = HAS_LOCAL_FLAG | HAS_PURE_FLAG, + [_LOAD_FAST_3] = HAS_LOCAL_FLAG | HAS_PURE_FLAG, + [_LOAD_FAST_4] = HAS_LOCAL_FLAG | HAS_PURE_FLAG, + [_LOAD_FAST_5] = HAS_LOCAL_FLAG | HAS_PURE_FLAG, + [_LOAD_FAST_6] = HAS_LOCAL_FLAG | HAS_PURE_FLAG, + [_LOAD_FAST_7] = HAS_LOCAL_FLAG | HAS_PURE_FLAG, [_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG, [_LOAD_FAST_AND_CLEAR] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, [_LOAD_FAST_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, [_LOAD_CONST] = HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_PURE_FLAG, + [_STORE_FAST_0] = HAS_LOCAL_FLAG, + [_STORE_FAST_1] = HAS_LOCAL_FLAG, + [_STORE_FAST_2] = HAS_LOCAL_FLAG, + [_STORE_FAST_3] = HAS_LOCAL_FLAG, + [_STORE_FAST_4] = HAS_LOCAL_FLAG, + [_STORE_FAST_5] = HAS_LOCAL_FLAG, + [_STORE_FAST_6] = HAS_LOCAL_FLAG, + [_STORE_FAST_7] = HAS_LOCAL_FLAG, [_STORE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, [_STORE_FAST_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, [_STORE_FAST_STORE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, @@ -85,17 +102,11 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_LOAD_LOCALS] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_LOAD_FROM_DICT_OR_GLOBALS] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_LOAD_NAME] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_LOAD_GLOBAL_0] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_LOAD_GLOBAL_1] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_LOAD_GLOBAL] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_OPARG_AND_1_FLAG, + [_LOAD_GLOBAL] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_GUARD_GLOBALS_VERSION] = HAS_DEOPT_FLAG, [_GUARD_BUILTINS_VERSION] = HAS_DEOPT_FLAG, - [_LOAD_GLOBAL_MODULE_0] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_LOAD_GLOBAL_MODULE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_LOAD_GLOBAL_MODULE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_OPARG_AND_1_FLAG, - [_LOAD_GLOBAL_BUILTINS_0] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_LOAD_GLOBAL_BUILTINS_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_LOAD_GLOBAL_BUILTINS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_OPARG_AND_1_FLAG, + [_LOAD_GLOBAL_MODULE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_GLOBAL_BUILTINS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, [_DELETE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ERROR_FLAG, [_MAKE_CELL] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_DELETE_DEREF] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -117,28 +128,22 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_MAP_ADD] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_LOAD_SUPER_ATTR_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_LOAD_SUPER_ATTR_METHOD] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_LOAD_ATTR_0] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_LOAD_ATTR_1] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_LOAD_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_OPARG_AND_1_FLAG, + [_LOAD_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_GUARD_TYPE_VERSION] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, [_CHECK_MANAGED_OBJECT_HAS_VALUES] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, - [_LOAD_ATTR_INSTANCE_VALUE_0] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_LOAD_ATTR_INSTANCE_VALUE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_ATTR_INSTANCE_VALUE_0] = HAS_DEOPT_FLAG, + [_LOAD_ATTR_INSTANCE_VALUE_1] = HAS_DEOPT_FLAG, [_LOAD_ATTR_INSTANCE_VALUE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_OPARG_AND_1_FLAG, [_CHECK_ATTR_MODULE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, - [_LOAD_ATTR_MODULE_0] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_LOAD_ATTR_MODULE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_LOAD_ATTR_MODULE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_OPARG_AND_1_FLAG, + [_LOAD_ATTR_MODULE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, [_CHECK_ATTR_WITH_HINT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG | HAS_PASSTHROUGH_FLAG, - [_LOAD_ATTR_WITH_HINT_0] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, - [_LOAD_ATTR_WITH_HINT_1] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, - [_LOAD_ATTR_WITH_HINT] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG | HAS_OPARG_AND_1_FLAG, - [_LOAD_ATTR_SLOT_0] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_LOAD_ATTR_SLOT_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_LOAD_ATTR_WITH_HINT] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, + [_LOAD_ATTR_SLOT_0] = HAS_DEOPT_FLAG, + [_LOAD_ATTR_SLOT_1] = HAS_DEOPT_FLAG, [_LOAD_ATTR_SLOT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_OPARG_AND_1_FLAG, [_CHECK_ATTR_CLASS] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, - [_LOAD_ATTR_CLASS_0] = HAS_ARG_FLAG, - [_LOAD_ATTR_CLASS_1] = HAS_ARG_FLAG, + [_LOAD_ATTR_CLASS_0] = 0, + [_LOAD_ATTR_CLASS_1] = 0, [_LOAD_ATTR_CLASS] = HAS_ARG_FLAG | HAS_OPARG_AND_1_FLAG, [_GUARD_DORV_VALUES] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, [_STORE_ATTR_INSTANCE_VALUE] = HAS_ESCAPES_FLAG, @@ -186,6 +191,11 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_CHECK_PEP_523] = HAS_DEOPT_FLAG, [_CHECK_FUNCTION_EXACT_ARGS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, [_CHECK_STACK_SPACE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_INIT_CALL_PY_EXACT_ARGS_0] = HAS_ESCAPES_FLAG | HAS_PURE_FLAG, + [_INIT_CALL_PY_EXACT_ARGS_1] = HAS_ESCAPES_FLAG | HAS_PURE_FLAG, + [_INIT_CALL_PY_EXACT_ARGS_2] = HAS_ESCAPES_FLAG | HAS_PURE_FLAG, + [_INIT_CALL_PY_EXACT_ARGS_3] = HAS_ESCAPES_FLAG | HAS_PURE_FLAG, + [_INIT_CALL_PY_EXACT_ARGS_4] = HAS_ESCAPES_FLAG | HAS_PURE_FLAG, [_INIT_CALL_PY_EXACT_ARGS] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG | HAS_PURE_FLAG, [_PUSH_FRAME] = HAS_ESCAPES_FLAG, [_CALL_TYPE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, @@ -230,6 +240,12 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_CHECK_VALIDITY_AND_SET_IP] = HAS_DEOPT_FLAG, }; +const uint8_t _PyUop_Replication[MAX_UOP_ID+1] = { + [_LOAD_FAST] = 8, + [_STORE_FAST] = 8, + [_INIT_CALL_PY_EXACT_ARGS] = 5, +}; + const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_BEFORE_ASYNC_WITH] = "_BEFORE_ASYNC_WITH", [_BEFORE_WITH] = "_BEFORE_WITH", @@ -330,6 +346,11 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_GUARD_TYPE_VERSION] = "_GUARD_TYPE_VERSION", [_INIT_CALL_BOUND_METHOD_EXACT_ARGS] = "_INIT_CALL_BOUND_METHOD_EXACT_ARGS", [_INIT_CALL_PY_EXACT_ARGS] = "_INIT_CALL_PY_EXACT_ARGS", + [_INIT_CALL_PY_EXACT_ARGS_0] = "_INIT_CALL_PY_EXACT_ARGS_0", + [_INIT_CALL_PY_EXACT_ARGS_1] = "_INIT_CALL_PY_EXACT_ARGS_1", + [_INIT_CALL_PY_EXACT_ARGS_2] = "_INIT_CALL_PY_EXACT_ARGS_2", + [_INIT_CALL_PY_EXACT_ARGS_3] = "_INIT_CALL_PY_EXACT_ARGS_3", + [_INIT_CALL_PY_EXACT_ARGS_4] = "_INIT_CALL_PY_EXACT_ARGS_4", [_INTERNAL_INCREMENT_OPT_COUNTER] = "_INTERNAL_INCREMENT_OPT_COUNTER", [_IS_NONE] = "_IS_NONE", [_IS_OP] = "_IS_OP", @@ -344,8 +365,6 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_LIST_EXTEND] = "_LIST_EXTEND", [_LOAD_ASSERTION_ERROR] = "_LOAD_ASSERTION_ERROR", [_LOAD_ATTR] = "_LOAD_ATTR", - [_LOAD_ATTR_0] = "_LOAD_ATTR_0", - [_LOAD_ATTR_1] = "_LOAD_ATTR_1", [_LOAD_ATTR_CLASS] = "_LOAD_ATTR_CLASS", [_LOAD_ATTR_CLASS_0] = "_LOAD_ATTR_CLASS_0", [_LOAD_ATTR_CLASS_1] = "_LOAD_ATTR_CLASS_1", @@ -356,16 +375,12 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_LOAD_ATTR_METHOD_NO_DICT] = "_LOAD_ATTR_METHOD_NO_DICT", [_LOAD_ATTR_METHOD_WITH_VALUES] = "_LOAD_ATTR_METHOD_WITH_VALUES", [_LOAD_ATTR_MODULE] = "_LOAD_ATTR_MODULE", - [_LOAD_ATTR_MODULE_0] = "_LOAD_ATTR_MODULE_0", - [_LOAD_ATTR_MODULE_1] = "_LOAD_ATTR_MODULE_1", [_LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = "_LOAD_ATTR_NONDESCRIPTOR_NO_DICT", [_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = "_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", [_LOAD_ATTR_SLOT] = "_LOAD_ATTR_SLOT", [_LOAD_ATTR_SLOT_0] = "_LOAD_ATTR_SLOT_0", [_LOAD_ATTR_SLOT_1] = "_LOAD_ATTR_SLOT_1", [_LOAD_ATTR_WITH_HINT] = "_LOAD_ATTR_WITH_HINT", - [_LOAD_ATTR_WITH_HINT_0] = "_LOAD_ATTR_WITH_HINT_0", - [_LOAD_ATTR_WITH_HINT_1] = "_LOAD_ATTR_WITH_HINT_1", [_LOAD_BUILD_CLASS] = "_LOAD_BUILD_CLASS", [_LOAD_CONST] = "_LOAD_CONST", [_LOAD_CONST_INLINE] = "_LOAD_CONST_INLINE", @@ -374,20 +389,22 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_LOAD_CONST_INLINE_WITH_NULL] = "_LOAD_CONST_INLINE_WITH_NULL", [_LOAD_DEREF] = "_LOAD_DEREF", [_LOAD_FAST] = "_LOAD_FAST", + [_LOAD_FAST_0] = "_LOAD_FAST_0", + [_LOAD_FAST_1] = "_LOAD_FAST_1", + [_LOAD_FAST_2] = "_LOAD_FAST_2", + [_LOAD_FAST_3] = "_LOAD_FAST_3", + [_LOAD_FAST_4] = "_LOAD_FAST_4", + [_LOAD_FAST_5] = "_LOAD_FAST_5", + [_LOAD_FAST_6] = "_LOAD_FAST_6", + [_LOAD_FAST_7] = "_LOAD_FAST_7", [_LOAD_FAST_AND_CLEAR] = "_LOAD_FAST_AND_CLEAR", [_LOAD_FAST_CHECK] = "_LOAD_FAST_CHECK", [_LOAD_FAST_LOAD_FAST] = "_LOAD_FAST_LOAD_FAST", [_LOAD_FROM_DICT_OR_DEREF] = "_LOAD_FROM_DICT_OR_DEREF", [_LOAD_FROM_DICT_OR_GLOBALS] = "_LOAD_FROM_DICT_OR_GLOBALS", [_LOAD_GLOBAL] = "_LOAD_GLOBAL", - [_LOAD_GLOBAL_0] = "_LOAD_GLOBAL_0", - [_LOAD_GLOBAL_1] = "_LOAD_GLOBAL_1", [_LOAD_GLOBAL_BUILTINS] = "_LOAD_GLOBAL_BUILTINS", - [_LOAD_GLOBAL_BUILTINS_0] = "_LOAD_GLOBAL_BUILTINS_0", - [_LOAD_GLOBAL_BUILTINS_1] = "_LOAD_GLOBAL_BUILTINS_1", [_LOAD_GLOBAL_MODULE] = "_LOAD_GLOBAL_MODULE", - [_LOAD_GLOBAL_MODULE_0] = "_LOAD_GLOBAL_MODULE_0", - [_LOAD_GLOBAL_MODULE_1] = "_LOAD_GLOBAL_MODULE_1", [_LOAD_LOCALS] = "_LOAD_LOCALS", [_LOAD_NAME] = "_LOAD_NAME", [_LOAD_SUPER_ATTR_ATTR] = "_LOAD_SUPER_ATTR_ATTR", @@ -418,6 +435,14 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_STORE_ATTR_SLOT] = "_STORE_ATTR_SLOT", [_STORE_DEREF] = "_STORE_DEREF", [_STORE_FAST] = "_STORE_FAST", + [_STORE_FAST_0] = "_STORE_FAST_0", + [_STORE_FAST_1] = "_STORE_FAST_1", + [_STORE_FAST_2] = "_STORE_FAST_2", + [_STORE_FAST_3] = "_STORE_FAST_3", + [_STORE_FAST_4] = "_STORE_FAST_4", + [_STORE_FAST_5] = "_STORE_FAST_5", + [_STORE_FAST_6] = "_STORE_FAST_6", + [_STORE_FAST_7] = "_STORE_FAST_7", [_STORE_FAST_LOAD_FAST] = "_STORE_FAST_LOAD_FAST", [_STORE_FAST_STORE_FAST] = "_STORE_FAST_STORE_FAST", [_STORE_GLOBAL] = "_STORE_GLOBAL", diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 1a8ed3441fa855..2d12d6520a0367 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -216,7 +216,7 @@ def testfunc(x): self.assertIsNotNone(ex) uops = {opname for opname, _, _ in ex} self.assertIn("_SET_IP", uops) - self.assertIn("_LOAD_FAST", uops) + self.assertIn("_LOAD_FAST_0", uops) def test_extended_arg(self): "Check EXTENDED_ARG handling in superblock creation" diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 28ade64e056ad7..72be15a22ae224 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -54,6 +54,8 @@ #define guard #define override #define specializing +#define split +#define replicate(TIMES) // Dummy variables for stack effects. static PyObject *value, *value1, *value2, *left, *right, *res, *sum, *prod, *sub; @@ -208,7 +210,7 @@ dummy_func( Py_INCREF(value); } - pure inst(LOAD_FAST, (-- value)) { + replicate(8) pure inst(LOAD_FAST, (-- value)) { value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -234,7 +236,7 @@ dummy_func( Py_INCREF(value); } - inst(STORE_FAST, (value --)) { + replicate(8) inst(STORE_FAST, (value --)) { SETLOCAL(oparg, value); } @@ -1914,7 +1916,7 @@ dummy_func( DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && !_PyObject_MakeInstanceAttributesFromDict(owner, dorv)); } - op(_LOAD_ATTR_INSTANCE_VALUE, (index/1, owner -- attr, null if (oparg & 1))) { + split op(_LOAD_ATTR_INSTANCE_VALUE, (index/1, owner -- attr, null if (oparg & 1))) { PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); attr = _PyDictOrValues_GetValues(dorv)->values[index]; DEOPT_IF(attr == NULL); @@ -1995,7 +1997,7 @@ dummy_func( _LOAD_ATTR_WITH_HINT + unused/5; - op(_LOAD_ATTR_SLOT, (index/1, owner -- attr, null if (oparg & 1))) { + split op(_LOAD_ATTR_SLOT, (index/1, owner -- attr, null if (oparg & 1))) { char *addr = (char *)owner + index; attr = *(PyObject **)addr; DEOPT_IF(attr == NULL); @@ -2018,7 +2020,7 @@ dummy_func( } - op(_LOAD_ATTR_CLASS, (descr/4, owner -- attr, null if (oparg & 1))) { + split op(_LOAD_ATTR_CLASS, (descr/4, owner -- attr, null if (oparg & 1))) { STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); attr = Py_NewRef(descr); @@ -2886,7 +2888,7 @@ dummy_func( DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version != keys_version); } - op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self if (1))) { + split op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self if (1))) { assert(oparg & 1); /* Cached method object */ STAT_INC(LOAD_ATTR, hit); @@ -3128,7 +3130,7 @@ dummy_func( DEOPT_IF(tstate->py_recursion_remaining <= 1); } - pure op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null, args[oparg] -- new_frame: _PyInterpreterFrame*)) { + replicate(5) pure op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null, args[oparg] -- new_frame: _PyInterpreterFrame*)) { int argcount = oparg; if (self_or_null != NULL) { args--; diff --git a/Python/ceval.c b/Python/ceval.c index 4f208009086191..780cbd6330b188 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1038,7 +1038,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int #ifdef Py_DEBUG { fprintf(stderr, "Unknown uop %d, oparg %d, operand %" PRIu64 " @ %d\n", - opcode, next_uop[-1].oparg, next_uop[-1].operand, + next_uop[-1].opcode, next_uop[-1].oparg, next_uop[-1].operand, (int)(next_uop - current_executor->trace - 1)); Py_FatalError("Unknown uop"); } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 65551a838b43cd..43d21f3072a917 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -37,6 +37,102 @@ break; } + case _LOAD_FAST_0: { + PyObject *value; + oparg = 0; + assert(oparg == CURRENT_OPARG()); + value = GETLOCAL(oparg); + assert(value != NULL); + Py_INCREF(value); + stack_pointer[0] = value; + stack_pointer += 1; + break; + } + + case _LOAD_FAST_1: { + PyObject *value; + oparg = 1; + assert(oparg == CURRENT_OPARG()); + value = GETLOCAL(oparg); + assert(value != NULL); + Py_INCREF(value); + stack_pointer[0] = value; + stack_pointer += 1; + break; + } + + case _LOAD_FAST_2: { + PyObject *value; + oparg = 2; + assert(oparg == CURRENT_OPARG()); + value = GETLOCAL(oparg); + assert(value != NULL); + Py_INCREF(value); + stack_pointer[0] = value; + stack_pointer += 1; + break; + } + + case _LOAD_FAST_3: { + PyObject *value; + oparg = 3; + assert(oparg == CURRENT_OPARG()); + value = GETLOCAL(oparg); + assert(value != NULL); + Py_INCREF(value); + stack_pointer[0] = value; + stack_pointer += 1; + break; + } + + case _LOAD_FAST_4: { + PyObject *value; + oparg = 4; + assert(oparg == CURRENT_OPARG()); + value = GETLOCAL(oparg); + assert(value != NULL); + Py_INCREF(value); + stack_pointer[0] = value; + stack_pointer += 1; + break; + } + + case _LOAD_FAST_5: { + PyObject *value; + oparg = 5; + assert(oparg == CURRENT_OPARG()); + value = GETLOCAL(oparg); + assert(value != NULL); + Py_INCREF(value); + stack_pointer[0] = value; + stack_pointer += 1; + break; + } + + case _LOAD_FAST_6: { + PyObject *value; + oparg = 6; + assert(oparg == CURRENT_OPARG()); + value = GETLOCAL(oparg); + assert(value != NULL); + Py_INCREF(value); + stack_pointer[0] = value; + stack_pointer += 1; + break; + } + + case _LOAD_FAST_7: { + PyObject *value; + oparg = 7; + assert(oparg == CURRENT_OPARG()); + value = GETLOCAL(oparg); + assert(value != NULL); + Py_INCREF(value); + stack_pointer[0] = value; + stack_pointer += 1; + break; + } + case _LOAD_FAST: { PyObject *value; oparg = CURRENT_OPARG(); @@ -69,6 +165,86 @@ break; } + case _STORE_FAST_0: { + PyObject *value; + oparg = 0; + assert(oparg == CURRENT_OPARG()); + value = stack_pointer[-1]; + SETLOCAL(oparg, value); + stack_pointer += -1; + break; + } + + case _STORE_FAST_1: { + PyObject *value; + oparg = 1; + assert(oparg == CURRENT_OPARG()); + value = stack_pointer[-1]; + SETLOCAL(oparg, value); + stack_pointer += -1; + break; + } + + case _STORE_FAST_2: { + PyObject *value; + oparg = 2; + assert(oparg == CURRENT_OPARG()); + value = stack_pointer[-1]; + SETLOCAL(oparg, value); + stack_pointer += -1; + break; + } + + case _STORE_FAST_3: { + PyObject *value; + oparg = 3; + assert(oparg == CURRENT_OPARG()); + value = stack_pointer[-1]; + SETLOCAL(oparg, value); + stack_pointer += -1; + break; + } + + case _STORE_FAST_4: { + PyObject *value; + oparg = 4; + assert(oparg == CURRENT_OPARG()); + value = stack_pointer[-1]; + SETLOCAL(oparg, value); + stack_pointer += -1; + break; + } + + case _STORE_FAST_5: { + PyObject *value; + oparg = 5; + assert(oparg == CURRENT_OPARG()); + value = stack_pointer[-1]; + SETLOCAL(oparg, value); + stack_pointer += -1; + break; + } + + case _STORE_FAST_6: { + PyObject *value; + oparg = 6; + assert(oparg == CURRENT_OPARG()); + value = stack_pointer[-1]; + SETLOCAL(oparg, value); + stack_pointer += -1; + break; + } + + case _STORE_FAST_7: { + PyObject *value; + oparg = 7; + assert(oparg == CURRENT_OPARG()); + value = stack_pointer[-1]; + SETLOCAL(oparg, value); + stack_pointer += -1; + break; + } + case _STORE_FAST: { PyObject *value; oparg = CURRENT_OPARG(); @@ -1087,50 +1263,7 @@ break; } - case _LOAD_GLOBAL_0: { - PyObject *res; - PyObject *null = NULL; - oparg = CURRENT_OPARG(); - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); - if (PyDict_CheckExact(GLOBALS()) - && PyDict_CheckExact(BUILTINS())) - { - res = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(), - (PyDictObject *)BUILTINS(), - name); - if (res == NULL) { - if (!_PyErr_Occurred(tstate)) { - /* _PyDict_LoadGlobal() returns NULL without raising - * an exception if the key doesn't exist */ - _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } - if (true) goto error_tier_two; - } - Py_INCREF(res); - } - else { - /* Slow-path if globals or builtins is not a dict */ - /* namespace 1: globals */ - if (PyMapping_GetOptionalItem(GLOBALS(), name, &res) < 0) goto error_tier_two; - if (res == NULL) { - /* namespace 2: builtins */ - if (PyMapping_GetOptionalItem(BUILTINS(), name, &res) < 0) goto error_tier_two; - if (res == NULL) { - _PyEval_FormatExcCheckArg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - if (true) goto error_tier_two; - } - } - } - null = NULL; - stack_pointer[0] = res; - stack_pointer += 1; - break; - } - - case _LOAD_GLOBAL_1: { + case _LOAD_GLOBAL: { PyObject *res; PyObject *null = NULL; oparg = CURRENT_OPARG(); @@ -1169,13 +1302,11 @@ } null = NULL; stack_pointer[0] = res; - stack_pointer[1] = null; - stack_pointer += 2; + if (oparg & 1) stack_pointer[1] = null; + stack_pointer += 1 + (oparg & 1); break; } - /* _LOAD_GLOBAL is split on (oparg & 1) */ - case _GUARD_GLOBALS_VERSION: { uint16_t version = (uint16_t)CURRENT_OPERAND(); PyDictObject *dict = (PyDictObject *)GLOBALS(); @@ -1194,24 +1325,7 @@ break; } - case _LOAD_GLOBAL_MODULE_0: { - PyObject *res; - PyObject *null = NULL; - oparg = CURRENT_OPARG(); - uint16_t index = (uint16_t)CURRENT_OPERAND(); - PyDictObject *dict = (PyDictObject *)GLOBALS(); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); - res = entries[index].me_value; - if (res == NULL) goto deoptimize; - Py_INCREF(res); - STAT_INC(LOAD_GLOBAL, hit); - null = NULL; - stack_pointer[0] = res; - stack_pointer += 1; - break; - } - - case _LOAD_GLOBAL_MODULE_1: { + case _LOAD_GLOBAL_MODULE: { PyObject *res; PyObject *null = NULL; oparg = CURRENT_OPARG(); @@ -1224,14 +1338,12 @@ STAT_INC(LOAD_GLOBAL, hit); null = NULL; stack_pointer[0] = res; - stack_pointer[1] = null; - stack_pointer += 2; + if (oparg & 1) stack_pointer[1] = null; + stack_pointer += 1 + (oparg & 1); break; } - /* _LOAD_GLOBAL_MODULE is split on (oparg & 1) */ - - case _LOAD_GLOBAL_BUILTINS_0: { + case _LOAD_GLOBAL_BUILTINS: { PyObject *res; PyObject *null = NULL; oparg = CURRENT_OPARG(); @@ -1244,30 +1356,11 @@ STAT_INC(LOAD_GLOBAL, hit); null = NULL; stack_pointer[0] = res; - stack_pointer += 1; + if (oparg & 1) stack_pointer[1] = null; + stack_pointer += 1 + (oparg & 1); break; } - case _LOAD_GLOBAL_BUILTINS_1: { - PyObject *res; - PyObject *null = NULL; - oparg = CURRENT_OPARG(); - uint16_t index = (uint16_t)CURRENT_OPERAND(); - PyDictObject *bdict = (PyDictObject *)BUILTINS(); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys); - res = entries[index].me_value; - if (res == NULL) goto deoptimize; - Py_INCREF(res); - STAT_INC(LOAD_GLOBAL, hit); - null = NULL; - stack_pointer[0] = res; - stack_pointer[1] = null; - stack_pointer += 2; - break; - } - - /* _LOAD_GLOBAL_BUILTINS is split on (oparg & 1) */ - case _DELETE_FAST: { oparg = CURRENT_OPARG(); PyObject *v = GETLOCAL(oparg); @@ -1595,11 +1688,7 @@ break; } - /* _INSTRUMENTED_LOAD_SUPER_ATTR_0 is not a viable micro-op for tier 2 */ - - /* _INSTRUMENTED_LOAD_SUPER_ATTR_1 is not a viable micro-op for tier 2 */ - - /* _INSTRUMENTED_LOAD_SUPER_ATTR is split on (oparg & 1) */ + /* _INSTRUMENTED_LOAD_SUPER_ATTR is not a viable micro-op for tier 2 */ case _LOAD_SUPER_ATTR_ATTR: { PyObject *self; @@ -1662,14 +1751,14 @@ break; } - case _LOAD_ATTR_0: { + case _LOAD_ATTR: { PyObject *owner; PyObject *attr; PyObject *self_or_null = NULL; oparg = CURRENT_OPARG(); owner = stack_pointer[-1]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); - if (0 ) { + if (oparg & 1) { /* Designed to work in tandem with CALL, pushes two values. */ attr = NULL; if (_PyObject_GetMethod(owner, name, &attr)) { @@ -1699,53 +1788,11 @@ if (attr == NULL) goto pop_1_error_tier_two; } stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = self_or_null; + stack_pointer += (oparg & 1); break; } - case _LOAD_ATTR_1: { - PyObject *owner; - PyObject *attr; - PyObject *self_or_null = NULL; - oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); - if (1 ) { - /* Designed to work in tandem with CALL, pushes two values. */ - attr = NULL; - if (_PyObject_GetMethod(owner, name, &attr)) { - /* We can bypass temporary bound method object. - meth is unbound method and obj is self. - meth | self | arg1 | ... | argN - */ - assert(attr != NULL); // No errors on this branch - self_or_null = owner; // Transfer ownership - } - else { - /* meth is not an unbound method (but a regular attr, or - something was returned by a descriptor protocol). Set - the second element of the stack to NULL, to signal - CALL that it's not a method call. - meth | NULL | arg1 | ... | argN - */ - Py_DECREF(owner); - if (attr == NULL) goto pop_1_error_tier_two; - self_or_null = NULL; - } - } - else { - /* Classic, pushes one value. */ - attr = PyObject_GetAttr(owner, name); - Py_DECREF(owner); - if (attr == NULL) goto pop_1_error_tier_two; - } - stack_pointer[-1] = attr; - stack_pointer[0] = self_or_null; - stack_pointer += 1; - break; - } - - /* _LOAD_ATTR is split on (oparg & 1) */ - case _GUARD_TYPE_VERSION: { PyObject *owner; owner = stack_pointer[-1]; @@ -1770,7 +1817,6 @@ PyObject *owner; PyObject *attr; PyObject *null = NULL; - oparg = CURRENT_OPARG(); owner = stack_pointer[-1]; uint16_t index = (uint16_t)CURRENT_OPERAND(); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); @@ -1788,7 +1834,6 @@ PyObject *owner; PyObject *attr; PyObject *null = NULL; - oparg = CURRENT_OPARG(); owner = stack_pointer[-1]; uint16_t index = (uint16_t)CURRENT_OPERAND(); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); @@ -1817,28 +1862,7 @@ break; } - case _LOAD_ATTR_MODULE_0: { - PyObject *owner; - PyObject *attr; - PyObject *null = NULL; - oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - uint16_t index = (uint16_t)CURRENT_OPERAND(); - PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; - assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE); - assert(index < dict->ma_keys->dk_nentries); - PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + index; - attr = ep->me_value; - if (attr == NULL) goto deoptimize; - STAT_INC(LOAD_ATTR, hit); - Py_INCREF(attr); - null = NULL; - Py_DECREF(owner); - stack_pointer[-1] = attr; - break; - } - - case _LOAD_ATTR_MODULE_1: { + case _LOAD_ATTR_MODULE: { PyObject *owner; PyObject *attr; PyObject *null = NULL; @@ -1856,13 +1880,11 @@ null = NULL; Py_DECREF(owner); stack_pointer[-1] = attr; - stack_pointer[0] = null; - stack_pointer += 1; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += (oparg & 1); break; } - /* _LOAD_ATTR_MODULE is split on (oparg & 1) */ - case _CHECK_ATTR_WITH_HINT: { PyObject *owner; owner = stack_pointer[-1]; @@ -1875,37 +1897,7 @@ break; } - case _LOAD_ATTR_WITH_HINT_0: { - PyObject *owner; - PyObject *attr; - PyObject *null = NULL; - oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - uint16_t hint = (uint16_t)CURRENT_OPERAND(); - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); - PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); - if (hint >= (size_t)dict->ma_keys->dk_nentries) goto deoptimize; - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); - if (DK_IS_UNICODE(dict->ma_keys)) { - PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; - if (ep->me_key != name) goto deoptimize; - attr = ep->me_value; - } - else { - PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint; - if (ep->me_key != name) goto deoptimize; - attr = ep->me_value; - } - if (attr == NULL) goto deoptimize; - STAT_INC(LOAD_ATTR, hit); - Py_INCREF(attr); - null = NULL; - Py_DECREF(owner); - stack_pointer[-1] = attr; - break; - } - - case _LOAD_ATTR_WITH_HINT_1: { + case _LOAD_ATTR_WITH_HINT: { PyObject *owner; PyObject *attr; PyObject *null = NULL; @@ -1932,18 +1924,15 @@ null = NULL; Py_DECREF(owner); stack_pointer[-1] = attr; - stack_pointer[0] = null; - stack_pointer += 1; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += (oparg & 1); break; } - /* _LOAD_ATTR_WITH_HINT is split on (oparg & 1) */ - case _LOAD_ATTR_SLOT_0: { PyObject *owner; PyObject *attr; PyObject *null = NULL; - oparg = CURRENT_OPARG(); owner = stack_pointer[-1]; uint16_t index = (uint16_t)CURRENT_OPERAND(); char *addr = (char *)owner + index; @@ -1961,7 +1950,6 @@ PyObject *owner; PyObject *attr; PyObject *null = NULL; - oparg = CURRENT_OPARG(); owner = stack_pointer[-1]; uint16_t index = (uint16_t)CURRENT_OPERAND(); char *addr = (char *)owner + index; @@ -1993,7 +1981,6 @@ PyObject *owner; PyObject *attr; PyObject *null = NULL; - oparg = CURRENT_OPARG(); owner = stack_pointer[-1]; PyObject *descr = (PyObject *)CURRENT_OPERAND(); STAT_INC(LOAD_ATTR, hit); @@ -2009,7 +1996,6 @@ PyObject *owner; PyObject *attr; PyObject *null = NULL; - oparg = CURRENT_OPARG(); owner = stack_pointer[-1]; PyObject *descr = (PyObject *)CURRENT_OPERAND(); STAT_INC(LOAD_ATTR, hit); @@ -2857,6 +2843,136 @@ break; } + case _INIT_CALL_PY_EXACT_ARGS_0: { + PyObject **args; + PyObject *self_or_null; + PyObject *callable; + _PyInterpreterFrame *new_frame; + oparg = 0; + assert(oparg == CURRENT_OPARG()); + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + int argcount = oparg; + if (self_or_null != NULL) { + args--; + argcount++; + } + STAT_INC(CALL, hit); + PyFunctionObject *func = (PyFunctionObject *)callable; + new_frame = _PyFrame_PushUnchecked(tstate, func, argcount); + for (int i = 0; i < argcount; i++) { + new_frame->localsplus[i] = args[i]; + } + stack_pointer[-2 - oparg] = (PyObject *)new_frame; + stack_pointer += -1 - oparg; + break; + } + + case _INIT_CALL_PY_EXACT_ARGS_1: { + PyObject **args; + PyObject *self_or_null; + PyObject *callable; + _PyInterpreterFrame *new_frame; + oparg = 1; + assert(oparg == CURRENT_OPARG()); + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + int argcount = oparg; + if (self_or_null != NULL) { + args--; + argcount++; + } + STAT_INC(CALL, hit); + PyFunctionObject *func = (PyFunctionObject *)callable; + new_frame = _PyFrame_PushUnchecked(tstate, func, argcount); + for (int i = 0; i < argcount; i++) { + new_frame->localsplus[i] = args[i]; + } + stack_pointer[-2 - oparg] = (PyObject *)new_frame; + stack_pointer += -1 - oparg; + break; + } + + case _INIT_CALL_PY_EXACT_ARGS_2: { + PyObject **args; + PyObject *self_or_null; + PyObject *callable; + _PyInterpreterFrame *new_frame; + oparg = 2; + assert(oparg == CURRENT_OPARG()); + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + int argcount = oparg; + if (self_or_null != NULL) { + args--; + argcount++; + } + STAT_INC(CALL, hit); + PyFunctionObject *func = (PyFunctionObject *)callable; + new_frame = _PyFrame_PushUnchecked(tstate, func, argcount); + for (int i = 0; i < argcount; i++) { + new_frame->localsplus[i] = args[i]; + } + stack_pointer[-2 - oparg] = (PyObject *)new_frame; + stack_pointer += -1 - oparg; + break; + } + + case _INIT_CALL_PY_EXACT_ARGS_3: { + PyObject **args; + PyObject *self_or_null; + PyObject *callable; + _PyInterpreterFrame *new_frame; + oparg = 3; + assert(oparg == CURRENT_OPARG()); + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + int argcount = oparg; + if (self_or_null != NULL) { + args--; + argcount++; + } + STAT_INC(CALL, hit); + PyFunctionObject *func = (PyFunctionObject *)callable; + new_frame = _PyFrame_PushUnchecked(tstate, func, argcount); + for (int i = 0; i < argcount; i++) { + new_frame->localsplus[i] = args[i]; + } + stack_pointer[-2 - oparg] = (PyObject *)new_frame; + stack_pointer += -1 - oparg; + break; + } + + case _INIT_CALL_PY_EXACT_ARGS_4: { + PyObject **args; + PyObject *self_or_null; + PyObject *callable; + _PyInterpreterFrame *new_frame; + oparg = 4; + assert(oparg == CURRENT_OPARG()); + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + int argcount = oparg; + if (self_or_null != NULL) { + args--; + argcount++; + } + STAT_INC(CALL, hit); + PyFunctionObject *func = (PyFunctionObject *)callable; + new_frame = _PyFrame_PushUnchecked(tstate, func, argcount); + for (int i = 0; i < argcount; i++) { + new_frame->localsplus[i] = args[i]; + } + stack_pointer[-2 - oparg] = (PyObject *)new_frame; + stack_pointer += -1 - oparg; + break; + } + case _INIT_CALL_PY_EXACT_ARGS: { PyObject **args; PyObject *self_or_null; @@ -3377,11 +3493,7 @@ /* _INSTRUMENTED_CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ - /* _CALL_FUNCTION_EX_0 is not a viable micro-op for tier 2 */ - - /* _CALL_FUNCTION_EX_1 is not a viable micro-op for tier 2 */ - - /* _CALL_FUNCTION_EX is split on (oparg & 1) */ + /* _CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ case _MAKE_FUNCTION: { PyObject *codeobj; diff --git a/Python/optimizer.c b/Python/optimizer.c index ee219a21a8bbbc..e3d547ec8f6d60 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -559,9 +559,6 @@ translate_bytecode_to_trace( for (int i = 0; i < nuops; i++) { oparg = orig_oparg; uint32_t uop = expansion->uops[i].uop; - if (_PyUop_Flags[uop] & HAS_OPARG_AND_1_FLAG) { - uop += 1 + (oparg & 1); - } uint64_t operand = 0; // Add one to account for the actual opcode/oparg pair: int offset = expansion->uops[i].offset + 1; @@ -849,6 +846,21 @@ uop_optimize( } } assert(err == 1); + /* Fix up */ + for (int pc = 0; pc < UOP_MAX_TRACE_LENGTH; pc++) { + int opcode = buffer[pc].opcode; + int oparg = buffer[pc].oparg; + if (_PyUop_Flags[opcode] & HAS_OPARG_AND_1_FLAG) { + buffer[pc].opcode = opcode + 1 + (oparg & 1); + } + else if (oparg < _PyUop_Replication[opcode]) { + buffer[pc].opcode = opcode + oparg + 1; + } + else if (opcode == _JUMP_TO_TOP || opcode == _EXIT_TRACE) { + break; + } + assert(_PyOpcode_uop_name[buffer[pc].opcode]); + } _PyExecutorObject *executor = make_executor_from_uops(buffer, &dependencies); if (executor == NULL) { return -1; diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index ee8f4ddc51b7cd..489b5be9ab65f0 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -416,7 +416,7 @@ globals_watcher_callback(PyDict_WatchEvent event, PyObject* dict, static void global_to_const(_PyUOpInstruction *inst, PyObject *obj) { - assert(PyDict_CheckExact(obj)); + assert(inst->opcode == _LOAD_GLOBAL_MODULE || inst->opcode == _LOAD_GLOBAL_BUILTINS); assert(PyDict_CheckExact(obj)); PyDictObject *dict = (PyDictObject *)obj; assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); @@ -527,15 +527,11 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, } break; case _LOAD_GLOBAL_BUILTINS: - case _LOAD_GLOBAL_BUILTINS_0: - case _LOAD_GLOBAL_BUILTINS_1: if (globals_checked & builtins_checked & globals_watched & builtins_watched & 1) { global_to_const(inst, builtins); } break; case _LOAD_GLOBAL_MODULE: - case _LOAD_GLOBAL_MODULE_0: - case _LOAD_GLOBAL_MODULE_1: if (globals_checked & globals_watched & 1) { global_to_const(inst, globals); } diff --git a/Python/tier2_redundancy_eliminator_cases.c.h b/Python/tier2_redundancy_eliminator_cases.c.h index 18d2efe2b06d6e..f37c5ce789c02a 100644 --- a/Python/tier2_redundancy_eliminator_cases.c.h +++ b/Python/tier2_redundancy_eliminator_cases.c.h @@ -619,31 +619,6 @@ break; } - case _LOAD_GLOBAL_0: { - _Py_UOpsSymType *res; - _Py_UOpsSymType *null = NULL; - res = sym_new_unknown(ctx); - if (res == NULL) goto out_of_space; - null = sym_new_null(ctx); - if (null == NULL) goto out_of_space; - stack_pointer[0] = res; - stack_pointer += 1; - break; - } - - case _LOAD_GLOBAL_1: { - _Py_UOpsSymType *res; - _Py_UOpsSymType *null = NULL; - res = sym_new_unknown(ctx); - if (res == NULL) goto out_of_space; - null = sym_new_null(ctx); - if (null == NULL) goto out_of_space; - stack_pointer[0] = res; - stack_pointer[1] = null; - stack_pointer += 2; - break; - } - case _LOAD_GLOBAL: { _Py_UOpsSymType *res; _Py_UOpsSymType *null = NULL; @@ -665,31 +640,6 @@ break; } - case _LOAD_GLOBAL_MODULE_0: { - _Py_UOpsSymType *res; - _Py_UOpsSymType *null = NULL; - res = sym_new_unknown(ctx); - if (res == NULL) goto out_of_space; - null = sym_new_null(ctx); - if (null == NULL) goto out_of_space; - stack_pointer[0] = res; - stack_pointer += 1; - break; - } - - case _LOAD_GLOBAL_MODULE_1: { - _Py_UOpsSymType *res; - _Py_UOpsSymType *null = NULL; - res = sym_new_unknown(ctx); - if (res == NULL) goto out_of_space; - null = sym_new_null(ctx); - if (null == NULL) goto out_of_space; - stack_pointer[0] = res; - stack_pointer[1] = null; - stack_pointer += 2; - break; - } - case _LOAD_GLOBAL_MODULE: { _Py_UOpsSymType *res; _Py_UOpsSymType *null = NULL; @@ -703,31 +653,6 @@ break; } - case _LOAD_GLOBAL_BUILTINS_0: { - _Py_UOpsSymType *res; - _Py_UOpsSymType *null = NULL; - res = sym_new_unknown(ctx); - if (res == NULL) goto out_of_space; - null = sym_new_null(ctx); - if (null == NULL) goto out_of_space; - stack_pointer[0] = res; - stack_pointer += 1; - break; - } - - case _LOAD_GLOBAL_BUILTINS_1: { - _Py_UOpsSymType *res; - _Py_UOpsSymType *null = NULL; - res = sym_new_unknown(ctx); - if (res == NULL) goto out_of_space; - null = sym_new_null(ctx); - if (null == NULL) goto out_of_space; - stack_pointer[0] = res; - stack_pointer[1] = null; - stack_pointer += 2; - break; - } - case _LOAD_GLOBAL_BUILTINS: { _Py_UOpsSymType *res; _Py_UOpsSymType *null = NULL; @@ -862,10 +787,6 @@ break; } - /* _INSTRUMENTED_LOAD_SUPER_ATTR_0 is not a viable micro-op for tier 2 */ - - /* _INSTRUMENTED_LOAD_SUPER_ATTR_1 is not a viable micro-op for tier 2 */ - /* _INSTRUMENTED_LOAD_SUPER_ATTR is not a viable micro-op for tier 2 */ case _LOAD_SUPER_ATTR_ATTR: { @@ -890,30 +811,6 @@ break; } - case _LOAD_ATTR_0: { - _Py_UOpsSymType *attr; - _Py_UOpsSymType *self_or_null = NULL; - attr = sym_new_unknown(ctx); - if (attr == NULL) goto out_of_space; - self_or_null = sym_new_unknown(ctx); - if (self_or_null == NULL) goto out_of_space; - stack_pointer[-1] = attr; - break; - } - - case _LOAD_ATTR_1: { - _Py_UOpsSymType *attr; - _Py_UOpsSymType *self_or_null = NULL; - attr = sym_new_unknown(ctx); - if (attr == NULL) goto out_of_space; - self_or_null = sym_new_unknown(ctx); - if (self_or_null == NULL) goto out_of_space; - stack_pointer[-1] = attr; - stack_pointer[0] = self_or_null; - stack_pointer += 1; - break; - } - case _LOAD_ATTR: { _Py_UOpsSymType *attr; _Py_UOpsSymType *self_or_null = NULL; @@ -936,27 +833,23 @@ } case _LOAD_ATTR_INSTANCE_VALUE_0: { - _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *null = NULL; - owner = stack_pointer[-1]; - uint16_t index = (uint16_t)this_instr->operand; - _LOAD_ATTR_NOT_NULL - (void)index; - (void)owner; + attr = sym_new_unknown(ctx); + if (attr == NULL) goto out_of_space; + null = sym_new_null(ctx); + if (null == NULL) goto out_of_space; stack_pointer[-1] = attr; break; } case _LOAD_ATTR_INSTANCE_VALUE_1: { - _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *null = NULL; - owner = stack_pointer[-1]; - uint16_t index = (uint16_t)this_instr->operand; - _LOAD_ATTR_NOT_NULL - (void)index; - (void)owner; + attr = sym_new_unknown(ctx); + if (attr == NULL) goto out_of_space; + null = sym_new_null(ctx); + if (null == NULL) goto out_of_space; stack_pointer[-1] = attr; stack_pointer[0] = null; stack_pointer += 1; @@ -982,34 +875,6 @@ break; } - case _LOAD_ATTR_MODULE_0: { - _Py_UOpsSymType *owner; - _Py_UOpsSymType *attr; - _Py_UOpsSymType *null = NULL; - owner = stack_pointer[-1]; - uint16_t index = (uint16_t)this_instr->operand; - _LOAD_ATTR_NOT_NULL - (void)index; - (void)owner; - stack_pointer[-1] = attr; - break; - } - - case _LOAD_ATTR_MODULE_1: { - _Py_UOpsSymType *owner; - _Py_UOpsSymType *attr; - _Py_UOpsSymType *null = NULL; - owner = stack_pointer[-1]; - uint16_t index = (uint16_t)this_instr->operand; - _LOAD_ATTR_NOT_NULL - (void)index; - (void)owner; - stack_pointer[-1] = attr; - stack_pointer[0] = null; - stack_pointer += 1; - break; - } - case _LOAD_ATTR_MODULE: { _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; @@ -1029,34 +894,6 @@ break; } - case _LOAD_ATTR_WITH_HINT_0: { - _Py_UOpsSymType *owner; - _Py_UOpsSymType *attr; - _Py_UOpsSymType *null = NULL; - owner = stack_pointer[-1]; - uint16_t hint = (uint16_t)this_instr->operand; - _LOAD_ATTR_NOT_NULL - (void)hint; - (void)owner; - stack_pointer[-1] = attr; - break; - } - - case _LOAD_ATTR_WITH_HINT_1: { - _Py_UOpsSymType *owner; - _Py_UOpsSymType *attr; - _Py_UOpsSymType *null = NULL; - owner = stack_pointer[-1]; - uint16_t hint = (uint16_t)this_instr->operand; - _LOAD_ATTR_NOT_NULL - (void)hint; - (void)owner; - stack_pointer[-1] = attr; - stack_pointer[0] = null; - stack_pointer += 1; - break; - } - case _LOAD_ATTR_WITH_HINT: { _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; @@ -1073,27 +910,23 @@ } case _LOAD_ATTR_SLOT_0: { - _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *null = NULL; - owner = stack_pointer[-1]; - uint16_t index = (uint16_t)this_instr->operand; - _LOAD_ATTR_NOT_NULL - (void)index; - (void)owner; + attr = sym_new_unknown(ctx); + if (attr == NULL) goto out_of_space; + null = sym_new_null(ctx); + if (null == NULL) goto out_of_space; stack_pointer[-1] = attr; break; } case _LOAD_ATTR_SLOT_1: { - _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *null = NULL; - owner = stack_pointer[-1]; - uint16_t index = (uint16_t)this_instr->operand; - _LOAD_ATTR_NOT_NULL - (void)index; - (void)owner; + attr = sym_new_unknown(ctx); + if (attr == NULL) goto out_of_space; + null = sym_new_null(ctx); + if (null == NULL) goto out_of_space; stack_pointer[-1] = attr; stack_pointer[0] = null; stack_pointer += 1; @@ -1120,27 +953,23 @@ } case _LOAD_ATTR_CLASS_0: { - _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *null = NULL; - owner = stack_pointer[-1]; - PyObject *descr = (PyObject *)this_instr->operand; - _LOAD_ATTR_NOT_NULL - (void)descr; - (void)owner; + attr = sym_new_unknown(ctx); + if (attr == NULL) goto out_of_space; + null = sym_new_null(ctx); + if (null == NULL) goto out_of_space; stack_pointer[-1] = attr; break; } case _LOAD_ATTR_CLASS_1: { - _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *null = NULL; - owner = stack_pointer[-1]; - PyObject *descr = (PyObject *)this_instr->operand; - _LOAD_ATTR_NOT_NULL - (void)descr; - (void)owner; + attr = sym_new_unknown(ctx); + if (attr == NULL) goto out_of_space; + null = sym_new_null(ctx); + if (null == NULL) goto out_of_space; stack_pointer[-1] = attr; stack_pointer[0] = null; stack_pointer += 1; @@ -1752,10 +1581,6 @@ /* _INSTRUMENTED_CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ - /* _CALL_FUNCTION_EX_0 is not a viable micro-op for tier 2 */ - - /* _CALL_FUNCTION_EX_1 is not a viable micro-op for tier 2 */ - /* _CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ case _MAKE_FUNCTION: { diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index 17f81bb3a0de11..2bf54a9fcf57a8 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -25,6 +25,7 @@ class Properties: pure: bool passthrough: bool oparg_and_1: bool = False + const_oparg: int = -1 def dump(self, indent: str) -> None: print(indent, end="") @@ -139,6 +140,8 @@ class Uop: properties: Properties _size: int = -1 implicitly_created: bool = False + replicated = 0 + replicates : "Uop | None" = None def dump(self, indent: str) -> None: print( @@ -444,7 +447,7 @@ def stack_effect_only_peeks(instr: parser.InstDef) -> bool: for s, other in zip(stack_inputs, instr.outputs) ) -OPARG_AND_1 = re.compile("\(*oparg *& *1") +OPARG_AND_1 = re.compile("\\(*oparg *& *1") def effect_depends_on_oparg_1(op: parser.InstDef) -> bool: for effect in op.inputs: @@ -502,10 +505,14 @@ def make_uop(name: str, op: parser.InstDef, inputs: list[parser.InputEffect], uo body=op.block.tokens, properties=compute_properties(op), ) - if effect_depends_on_oparg_1(op): + if effect_depends_on_oparg_1(op) and "split" in op.annotations: result.properties.oparg_and_1 = True for bit in ("0", "1"): name_x = name + "_" + bit + properties = compute_properties(op) + if properties.oparg: + # May not need oparg anymore + properties.oparg = any(token.text == "oparg" for token in op.block.tokens) uops[name_x] = Uop( name=name_x, context=op.context, @@ -513,8 +520,31 @@ def make_uop(name: str, op: parser.InstDef, inputs: list[parser.InputEffect], uo stack=analyze_stack(op, bit), caches=analyze_caches(inputs), body=op.block.tokens, - properties=compute_properties(op), + properties=properties, ) + for anno in op.annotations: + if anno.startswith("replicate"): + result.replicated = int(anno[10:-1]) + break + else: + return result + for oparg in range(result.replicated): + name_x = name + "_" + str(oparg) + properties = compute_properties(op) + properties.oparg = False + properties.const_oparg = oparg + rep = Uop( + name=name_x, + context=op.context, + annotations=op.annotations, + stack=analyze_stack(op), + caches=analyze_caches(inputs), + body=op.block.tokens, + properties=properties, + ) + rep.replicates = result + uops[name_x] = rep + return result diff --git a/Tools/cases_generator/lexer.py b/Tools/cases_generator/lexer.py index 4f8d01c5492f51..0077921e7d7fa1 100644 --- a/Tools/cases_generator/lexer.py +++ b/Tools/cases_generator/lexer.py @@ -222,6 +222,8 @@ def choice(*opts: str) -> str: "register", "replaced", "pure", + "split", + "replicate", } __all__ = [] diff --git a/Tools/cases_generator/parsing.py b/Tools/cases_generator/parsing.py index a8961f28babea1..0d54820e4e71fb 100644 --- a/Tools/cases_generator/parsing.py +++ b/Tools/cases_generator/parsing.py @@ -179,7 +179,13 @@ def inst_header(self) -> InstHeader | None: # | annotation* op(NAME, (inputs -- outputs)) annotations = [] while anno := self.expect(lx.ANNOTATION): - annotations.append(anno.text) + if anno.text == "replicate": + self.require(lx.LPAREN) + times = self.require(lx.NUMBER) + self.require(lx.RPAREN) + annotations.append(f"replicate({times.text})") + else: + annotations.append(anno.text) tkn = self.expect(lx.INST) if not tkn: tkn = self.expect(lx.OP) diff --git a/Tools/cases_generator/tier2_abstract_generator.py b/Tools/cases_generator/tier2_abstract_generator.py index cc29b1660d26ed..47a862643d987e 100644 --- a/Tools/cases_generator/tier2_abstract_generator.py +++ b/Tools/cases_generator/tier2_abstract_generator.py @@ -178,6 +178,8 @@ def generate_abstract_interpreter( validate_uop(override, uop) if uop.properties.tier_one_only: continue + if uop.replicates: + continue if uop.is_super(): continue if not uop.is_viable(): diff --git a/Tools/cases_generator/tier2_generator.py b/Tools/cases_generator/tier2_generator.py index 0093a1b12be8b9..d719445b2f8623 100644 --- a/Tools/cases_generator/tier2_generator.py +++ b/Tools/cases_generator/tier2_generator.py @@ -129,6 +129,10 @@ def write_uop(uop: Uop, out: CWriter, stack: Stack) -> None: out.start_line() if uop.properties.oparg: out.emit("oparg = CURRENT_OPARG();\n") + assert(uop.properties.const_oparg < 0) + elif uop.properties.const_oparg >= 0: + out.emit(f"oparg = {uop.properties.const_oparg};\n") + out.emit(f"assert(oparg == CURRENT_OPARG());\n") for var in reversed(uop.stack.inputs): out.emit(stack.pop(var)) if not uop.properties.stores_sp: diff --git a/Tools/cases_generator/uop_id_generator.py b/Tools/cases_generator/uop_id_generator.py index b7aa2351726408..907158f2795959 100644 --- a/Tools/cases_generator/uop_id_generator.py +++ b/Tools/cases_generator/uop_id_generator.py @@ -45,7 +45,7 @@ def generate_uop_ids( continue if uop.properties.tier_one_only: continue - if uop.implicitly_created and not distinct_namespace: + if uop.implicitly_created and not distinct_namespace and not uop.replicated: out.emit(f"#define {name} {name[1:]}\n") else: out.emit(f"#define {name} {next_id}\n") diff --git a/Tools/cases_generator/uop_metadata_generator.py b/Tools/cases_generator/uop_metadata_generator.py index 9083ecc48bdf5b..f85f1c6ce9c817 100644 --- a/Tools/cases_generator/uop_metadata_generator.py +++ b/Tools/cases_generator/uop_metadata_generator.py @@ -24,6 +24,7 @@ def generate_names_and_flags(analysis: Analysis, out: CWriter) -> None: out.emit("extern const uint16_t _PyUop_Flags[MAX_UOP_ID+1];\n") + out.emit("extern const uint8_t _PyUop_Replication[MAX_UOP_ID+1];\n") out.emit("extern const char * const _PyOpcode_uop_name[MAX_UOP_ID+1];\n\n") out.emit("#ifdef NEED_OPCODE_METADATA\n") out.emit("const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {\n") @@ -31,6 +32,12 @@ def generate_names_and_flags(analysis: Analysis, out: CWriter) -> None: if uop.is_viable() and not uop.properties.tier_one_only: out.emit(f"[{uop.name}] = {cflags(uop.properties)},\n") + out.emit("};\n\n") + out.emit("const uint8_t _PyUop_Replication[MAX_UOP_ID+1] = {\n") + for uop in analysis.uops.values(): + if uop.replicated: + out.emit(f"[{uop.name}] = {uop.replicated},\n") + out.emit("};\n\n") out.emit("const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = {\n") for uop in sorted(analysis.uops.values(), key=lambda t: t.name): From 97cf57e934c3b102a4167f3e7ff6747206180167 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 15 Feb 2024 06:32:29 +0000 Subject: [PATCH 4/5] Do not emit abstract interpreter code for replica uops --- Python/optimizer_analysis.c | 3 +- Python/tier2_redundancy_eliminator_cases.c.h | 72 -------------------- Tools/cases_generator/analyzer.py | 4 +- 3 files changed, 5 insertions(+), 74 deletions(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 489b5be9ab65f0..d73bc310345f41 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -416,7 +416,8 @@ globals_watcher_callback(PyDict_WatchEvent event, PyObject* dict, static void global_to_const(_PyUOpInstruction *inst, PyObject *obj) { - assert(inst->opcode == _LOAD_GLOBAL_MODULE || inst->opcode == _LOAD_GLOBAL_BUILTINS); assert(PyDict_CheckExact(obj)); + assert(inst->opcode == _LOAD_GLOBAL_MODULE || inst->opcode == _LOAD_GLOBAL_BUILTINS); + assert(PyDict_CheckExact(obj)); PyDictObject *dict = (PyDictObject *)obj; assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); diff --git a/Python/tier2_redundancy_eliminator_cases.c.h b/Python/tier2_redundancy_eliminator_cases.c.h index f37c5ce789c02a..8f27ddfaebcb77 100644 --- a/Python/tier2_redundancy_eliminator_cases.c.h +++ b/Python/tier2_redundancy_eliminator_cases.c.h @@ -832,30 +832,6 @@ break; } - case _LOAD_ATTR_INSTANCE_VALUE_0: { - _Py_UOpsSymType *attr; - _Py_UOpsSymType *null = NULL; - attr = sym_new_unknown(ctx); - if (attr == NULL) goto out_of_space; - null = sym_new_null(ctx); - if (null == NULL) goto out_of_space; - stack_pointer[-1] = attr; - break; - } - - case _LOAD_ATTR_INSTANCE_VALUE_1: { - _Py_UOpsSymType *attr; - _Py_UOpsSymType *null = NULL; - attr = sym_new_unknown(ctx); - if (attr == NULL) goto out_of_space; - null = sym_new_null(ctx); - if (null == NULL) goto out_of_space; - stack_pointer[-1] = attr; - stack_pointer[0] = null; - stack_pointer += 1; - break; - } - case _LOAD_ATTR_INSTANCE_VALUE: { _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; @@ -909,30 +885,6 @@ break; } - case _LOAD_ATTR_SLOT_0: { - _Py_UOpsSymType *attr; - _Py_UOpsSymType *null = NULL; - attr = sym_new_unknown(ctx); - if (attr == NULL) goto out_of_space; - null = sym_new_null(ctx); - if (null == NULL) goto out_of_space; - stack_pointer[-1] = attr; - break; - } - - case _LOAD_ATTR_SLOT_1: { - _Py_UOpsSymType *attr; - _Py_UOpsSymType *null = NULL; - attr = sym_new_unknown(ctx); - if (attr == NULL) goto out_of_space; - null = sym_new_null(ctx); - if (null == NULL) goto out_of_space; - stack_pointer[-1] = attr; - stack_pointer[0] = null; - stack_pointer += 1; - break; - } - case _LOAD_ATTR_SLOT: { _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; @@ -952,30 +904,6 @@ break; } - case _LOAD_ATTR_CLASS_0: { - _Py_UOpsSymType *attr; - _Py_UOpsSymType *null = NULL; - attr = sym_new_unknown(ctx); - if (attr == NULL) goto out_of_space; - null = sym_new_null(ctx); - if (null == NULL) goto out_of_space; - stack_pointer[-1] = attr; - break; - } - - case _LOAD_ATTR_CLASS_1: { - _Py_UOpsSymType *attr; - _Py_UOpsSymType *null = NULL; - attr = sym_new_unknown(ctx); - if (attr == NULL) goto out_of_space; - null = sym_new_null(ctx); - if (null == NULL) goto out_of_space; - stack_pointer[-1] = attr; - stack_pointer[0] = null; - stack_pointer += 1; - break; - } - case _LOAD_ATTR_CLASS: { _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index 2bf54a9fcf57a8..ccba9253acb87a 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -513,7 +513,7 @@ def make_uop(name: str, op: parser.InstDef, inputs: list[parser.InputEffect], uo if properties.oparg: # May not need oparg anymore properties.oparg = any(token.text == "oparg" for token in op.block.tokens) - uops[name_x] = Uop( + rep = Uop( name=name_x, context=op.context, annotations=op.annotations, @@ -522,6 +522,8 @@ def make_uop(name: str, op: parser.InstDef, inputs: list[parser.InputEffect], uo body=op.block.tokens, properties=properties, ) + rep.replicates = result + uops[name_x] = rep for anno in op.annotations: if anno.startswith("replicate"): result.replicated = int(anno[10:-1]) From f99858c834e538069dbd721fd231bd4a6b5ca949 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 15 Feb 2024 13:14:07 +0000 Subject: [PATCH 5/5] Address review comments --- Python/executor_cases.c.h | 6 ++++ Tools/cases_generator/tier2_generator.py | 38 ++++++++++++++---------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 43d21f3072a917..ec9c22792b3cda 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1817,6 +1817,7 @@ PyObject *owner; PyObject *attr; PyObject *null = NULL; + (void)null; owner = stack_pointer[-1]; uint16_t index = (uint16_t)CURRENT_OPERAND(); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); @@ -1834,6 +1835,7 @@ PyObject *owner; PyObject *attr; PyObject *null = NULL; + (void)null; owner = stack_pointer[-1]; uint16_t index = (uint16_t)CURRENT_OPERAND(); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); @@ -1933,6 +1935,7 @@ PyObject *owner; PyObject *attr; PyObject *null = NULL; + (void)null; owner = stack_pointer[-1]; uint16_t index = (uint16_t)CURRENT_OPERAND(); char *addr = (char *)owner + index; @@ -1950,6 +1953,7 @@ PyObject *owner; PyObject *attr; PyObject *null = NULL; + (void)null; owner = stack_pointer[-1]; uint16_t index = (uint16_t)CURRENT_OPERAND(); char *addr = (char *)owner + index; @@ -1981,6 +1985,7 @@ PyObject *owner; PyObject *attr; PyObject *null = NULL; + (void)null; owner = stack_pointer[-1]; PyObject *descr = (PyObject *)CURRENT_OPERAND(); STAT_INC(LOAD_ATTR, hit); @@ -1996,6 +2001,7 @@ PyObject *owner; PyObject *attr; PyObject *null = NULL; + (void)null; owner = stack_pointer[-1]; PyObject *descr = (PyObject *)CURRENT_OPERAND(); STAT_INC(LOAD_ATTR, hit); diff --git a/Tools/cases_generator/tier2_generator.py b/Tools/cases_generator/tier2_generator.py index d719445b2f8623..30df46ec23bcba 100644 --- a/Tools/cases_generator/tier2_generator.py +++ b/Tools/cases_generator/tier2_generator.py @@ -33,24 +33,29 @@ DEFAULT_OUTPUT = ROOT / "Python/executor_cases.c.h" +def declare_variable( + var: StackItem, uop: Uop, variables: set[str], out: CWriter +) -> None: + if var.name in variables: + return + type = var.type if var.type else "PyObject *" + variables.add(var.name) + if var.condition: + out.emit(f"{type}{var.name} = NULL;\n") + if uop.replicates: + # Replicas may not use all their conditional variables + # So avoid a compiler warning with a fake use + out.emit(f"(void){var.name};\n") + else: + out.emit(f"{type}{var.name};\n") + + def declare_variables(uop: Uop, out: CWriter) -> None: variables = {"unused"} for var in reversed(uop.stack.inputs): - if var.name not in variables: - type = var.type if var.type else "PyObject *" - variables.add(var.name) - if var.condition: - out.emit(f"{type}{var.name} = NULL;\n") - else: - out.emit(f"{type}{var.name};\n") + declare_variable(var, uop, variables, out) for var in uop.stack.outputs: - if var.name not in variables: - variables.add(var.name) - type = var.type if var.type else "PyObject *" - if var.condition: - out.emit(f"{type}{var.name} = NULL;\n") - else: - out.emit(f"{type}{var.name};\n") + declare_variable(var, uop, variables, out) def tier2_replace_error( @@ -115,9 +120,10 @@ def tier2_replace_oparg( out.emit(amp) return one = next(tkn_iter) - assert(one.text == "1") + assert one.text == "1" out.emit_at(uop.name[-1], tkn) + TIER2_REPLACEMENT_FUNCTIONS = REPLACEMENT_FUNCTIONS.copy() TIER2_REPLACEMENT_FUNCTIONS["ERROR_IF"] = tier2_replace_error TIER2_REPLACEMENT_FUNCTIONS["DEOPT_IF"] = tier2_replace_deopt @@ -129,7 +135,7 @@ def write_uop(uop: Uop, out: CWriter, stack: Stack) -> None: out.start_line() if uop.properties.oparg: out.emit("oparg = CURRENT_OPARG();\n") - assert(uop.properties.const_oparg < 0) + assert uop.properties.const_oparg < 0 elif uop.properties.const_oparg >= 0: out.emit(f"oparg = {uop.properties.const_oparg};\n") out.emit(f"assert(oparg == CURRENT_OPARG());\n")