GH-111485: Generate instruction and uop metadata (GH-113287)

This commit is contained in:
Mark Shannon 2023-12-20 14:27:25 +00:00 committed by GitHub
parent a545a86ec6
commit e96f26083b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 1738 additions and 1269 deletions

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,7 @@
// from: // from:
// Python/bytecodes.c // Python/bytecodes.c
// Do not edit! // Do not edit!
#ifndef Py_CORE_UOP_IDS_H #ifndef Py_CORE_UOP_IDS_H
#define Py_CORE_UOP_IDS_H #define Py_CORE_UOP_IDS_H
#ifdef __cplusplus #ifdef __cplusplus
@ -11,7 +12,6 @@ extern "C" {
#define _EXIT_TRACE 300 #define _EXIT_TRACE 300
#define _SET_IP 301 #define _SET_IP 301
#define _NOP NOP #define _NOP NOP
#define _RESUME RESUME
#define _RESUME_CHECK RESUME_CHECK #define _RESUME_CHECK RESUME_CHECK
#define _INSTRUMENTED_RESUME INSTRUMENTED_RESUME #define _INSTRUMENTED_RESUME INSTRUMENTED_RESUME
#define _LOAD_FAST_CHECK LOAD_FAST_CHECK #define _LOAD_FAST_CHECK LOAD_FAST_CHECK
@ -24,13 +24,10 @@ extern "C" {
#define _STORE_FAST_STORE_FAST STORE_FAST_STORE_FAST #define _STORE_FAST_STORE_FAST STORE_FAST_STORE_FAST
#define _POP_TOP POP_TOP #define _POP_TOP POP_TOP
#define _PUSH_NULL PUSH_NULL #define _PUSH_NULL PUSH_NULL
#define _INSTRUMENTED_END_FOR INSTRUMENTED_END_FOR
#define _END_SEND END_SEND #define _END_SEND END_SEND
#define _INSTRUMENTED_END_SEND INSTRUMENTED_END_SEND
#define _UNARY_NEGATIVE UNARY_NEGATIVE #define _UNARY_NEGATIVE UNARY_NEGATIVE
#define _UNARY_NOT UNARY_NOT #define _UNARY_NOT UNARY_NOT
#define _SPECIALIZE_TO_BOOL 302 #define _TO_BOOL 302
#define _TO_BOOL 303
#define _TO_BOOL_BOOL TO_BOOL_BOOL #define _TO_BOOL_BOOL TO_BOOL_BOOL
#define _TO_BOOL_INT TO_BOOL_INT #define _TO_BOOL_INT TO_BOOL_INT
#define _TO_BOOL_LIST TO_BOOL_LIST #define _TO_BOOL_LIST TO_BOOL_LIST
@ -38,19 +35,17 @@ extern "C" {
#define _TO_BOOL_STR TO_BOOL_STR #define _TO_BOOL_STR TO_BOOL_STR
#define _TO_BOOL_ALWAYS_TRUE TO_BOOL_ALWAYS_TRUE #define _TO_BOOL_ALWAYS_TRUE TO_BOOL_ALWAYS_TRUE
#define _UNARY_INVERT UNARY_INVERT #define _UNARY_INVERT UNARY_INVERT
#define _GUARD_BOTH_INT 304 #define _GUARD_BOTH_INT 303
#define _BINARY_OP_MULTIPLY_INT 305 #define _BINARY_OP_MULTIPLY_INT 304
#define _BINARY_OP_ADD_INT 306 #define _BINARY_OP_ADD_INT 305
#define _BINARY_OP_SUBTRACT_INT 307 #define _BINARY_OP_SUBTRACT_INT 306
#define _GUARD_BOTH_FLOAT 308 #define _GUARD_BOTH_FLOAT 307
#define _BINARY_OP_MULTIPLY_FLOAT 309 #define _BINARY_OP_MULTIPLY_FLOAT 308
#define _BINARY_OP_ADD_FLOAT 310 #define _BINARY_OP_ADD_FLOAT 309
#define _BINARY_OP_SUBTRACT_FLOAT 311 #define _BINARY_OP_SUBTRACT_FLOAT 310
#define _GUARD_BOTH_UNICODE 312 #define _GUARD_BOTH_UNICODE 311
#define _BINARY_OP_ADD_UNICODE 313 #define _BINARY_OP_ADD_UNICODE 312
#define _BINARY_OP_INPLACE_ADD_UNICODE 314 #define _BINARY_SUBSCR 313
#define _SPECIALIZE_BINARY_SUBSCR 315
#define _BINARY_SUBSCR 316
#define _BINARY_SLICE BINARY_SLICE #define _BINARY_SLICE BINARY_SLICE
#define _STORE_SLICE STORE_SLICE #define _STORE_SLICE STORE_SLICE
#define _BINARY_SUBSCR_LIST_INT BINARY_SUBSCR_LIST_INT #define _BINARY_SUBSCR_LIST_INT BINARY_SUBSCR_LIST_INT
@ -60,54 +55,43 @@ extern "C" {
#define _BINARY_SUBSCR_GETITEM BINARY_SUBSCR_GETITEM #define _BINARY_SUBSCR_GETITEM BINARY_SUBSCR_GETITEM
#define _LIST_APPEND LIST_APPEND #define _LIST_APPEND LIST_APPEND
#define _SET_ADD SET_ADD #define _SET_ADD SET_ADD
#define _SPECIALIZE_STORE_SUBSCR 317 #define _STORE_SUBSCR 314
#define _STORE_SUBSCR 318
#define _STORE_SUBSCR_LIST_INT STORE_SUBSCR_LIST_INT #define _STORE_SUBSCR_LIST_INT STORE_SUBSCR_LIST_INT
#define _STORE_SUBSCR_DICT STORE_SUBSCR_DICT #define _STORE_SUBSCR_DICT STORE_SUBSCR_DICT
#define _DELETE_SUBSCR DELETE_SUBSCR #define _DELETE_SUBSCR DELETE_SUBSCR
#define _CALL_INTRINSIC_1 CALL_INTRINSIC_1 #define _CALL_INTRINSIC_1 CALL_INTRINSIC_1
#define _CALL_INTRINSIC_2 CALL_INTRINSIC_2 #define _CALL_INTRINSIC_2 CALL_INTRINSIC_2
#define _RAISE_VARARGS RAISE_VARARGS #define _POP_FRAME 315
#define _INTERPRETER_EXIT INTERPRETER_EXIT
#define _POP_FRAME 319
#define _INSTRUMENTED_RETURN_VALUE INSTRUMENTED_RETURN_VALUE #define _INSTRUMENTED_RETURN_VALUE INSTRUMENTED_RETURN_VALUE
#define _INSTRUMENTED_RETURN_CONST INSTRUMENTED_RETURN_CONST #define _INSTRUMENTED_RETURN_CONST INSTRUMENTED_RETURN_CONST
#define _GET_AITER GET_AITER #define _GET_AITER GET_AITER
#define _GET_ANEXT GET_ANEXT #define _GET_ANEXT GET_ANEXT
#define _GET_AWAITABLE GET_AWAITABLE #define _GET_AWAITABLE GET_AWAITABLE
#define _SPECIALIZE_SEND 320 #define _SEND 316
#define _SEND 321
#define _SEND_GEN SEND_GEN #define _SEND_GEN SEND_GEN
#define _INSTRUMENTED_YIELD_VALUE INSTRUMENTED_YIELD_VALUE #define _INSTRUMENTED_YIELD_VALUE INSTRUMENTED_YIELD_VALUE
#define _YIELD_VALUE YIELD_VALUE
#define _POP_EXCEPT POP_EXCEPT #define _POP_EXCEPT POP_EXCEPT
#define _RERAISE RERAISE
#define _END_ASYNC_FOR END_ASYNC_FOR
#define _CLEANUP_THROW CLEANUP_THROW
#define _LOAD_ASSERTION_ERROR LOAD_ASSERTION_ERROR #define _LOAD_ASSERTION_ERROR LOAD_ASSERTION_ERROR
#define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS
#define _STORE_NAME STORE_NAME #define _STORE_NAME STORE_NAME
#define _DELETE_NAME DELETE_NAME #define _DELETE_NAME DELETE_NAME
#define _SPECIALIZE_UNPACK_SEQUENCE 322 #define _UNPACK_SEQUENCE 317
#define _UNPACK_SEQUENCE 323
#define _UNPACK_SEQUENCE_TWO_TUPLE UNPACK_SEQUENCE_TWO_TUPLE #define _UNPACK_SEQUENCE_TWO_TUPLE UNPACK_SEQUENCE_TWO_TUPLE
#define _UNPACK_SEQUENCE_TUPLE UNPACK_SEQUENCE_TUPLE #define _UNPACK_SEQUENCE_TUPLE UNPACK_SEQUENCE_TUPLE
#define _UNPACK_SEQUENCE_LIST UNPACK_SEQUENCE_LIST #define _UNPACK_SEQUENCE_LIST UNPACK_SEQUENCE_LIST
#define _UNPACK_EX UNPACK_EX #define _UNPACK_EX UNPACK_EX
#define _SPECIALIZE_STORE_ATTR 324 #define _STORE_ATTR 318
#define _STORE_ATTR 325
#define _DELETE_ATTR DELETE_ATTR #define _DELETE_ATTR DELETE_ATTR
#define _STORE_GLOBAL STORE_GLOBAL #define _STORE_GLOBAL STORE_GLOBAL
#define _DELETE_GLOBAL DELETE_GLOBAL #define _DELETE_GLOBAL DELETE_GLOBAL
#define _LOAD_LOCALS LOAD_LOCALS #define _LOAD_LOCALS LOAD_LOCALS
#define _LOAD_FROM_DICT_OR_GLOBALS LOAD_FROM_DICT_OR_GLOBALS #define _LOAD_FROM_DICT_OR_GLOBALS LOAD_FROM_DICT_OR_GLOBALS
#define _LOAD_NAME LOAD_NAME #define _LOAD_NAME LOAD_NAME
#define _SPECIALIZE_LOAD_GLOBAL 326 #define _LOAD_GLOBAL 319
#define _LOAD_GLOBAL 327 #define _GUARD_GLOBALS_VERSION 320
#define _GUARD_GLOBALS_VERSION 328 #define _GUARD_BUILTINS_VERSION 321
#define _GUARD_BUILTINS_VERSION 329 #define _LOAD_GLOBAL_MODULE 322
#define _LOAD_GLOBAL_MODULE 330 #define _LOAD_GLOBAL_BUILTINS 323
#define _LOAD_GLOBAL_BUILTINS 331
#define _DELETE_FAST DELETE_FAST #define _DELETE_FAST DELETE_FAST
#define _MAKE_CELL MAKE_CELL #define _MAKE_CELL MAKE_CELL
#define _DELETE_DEREF DELETE_DEREF #define _DELETE_DEREF DELETE_DEREF
@ -128,30 +112,26 @@ extern "C" {
#define _DICT_MERGE DICT_MERGE #define _DICT_MERGE DICT_MERGE
#define _MAP_ADD MAP_ADD #define _MAP_ADD MAP_ADD
#define _INSTRUMENTED_LOAD_SUPER_ATTR INSTRUMENTED_LOAD_SUPER_ATTR #define _INSTRUMENTED_LOAD_SUPER_ATTR INSTRUMENTED_LOAD_SUPER_ATTR
#define _SPECIALIZE_LOAD_SUPER_ATTR 332
#define _LOAD_SUPER_ATTR 333
#define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR
#define _LOAD_SUPER_ATTR_METHOD LOAD_SUPER_ATTR_METHOD #define _LOAD_SUPER_ATTR_METHOD LOAD_SUPER_ATTR_METHOD
#define _SPECIALIZE_LOAD_ATTR 334 #define _LOAD_ATTR 324
#define _LOAD_ATTR 335 #define _GUARD_TYPE_VERSION 325
#define _GUARD_TYPE_VERSION 336 #define _CHECK_MANAGED_OBJECT_HAS_VALUES 326
#define _CHECK_MANAGED_OBJECT_HAS_VALUES 337 #define _LOAD_ATTR_INSTANCE_VALUE 327
#define _LOAD_ATTR_INSTANCE_VALUE 338 #define _CHECK_ATTR_MODULE 328
#define _CHECK_ATTR_MODULE 339 #define _LOAD_ATTR_MODULE 329
#define _LOAD_ATTR_MODULE 340 #define _CHECK_ATTR_WITH_HINT 330
#define _CHECK_ATTR_WITH_HINT 341 #define _LOAD_ATTR_WITH_HINT 331
#define _LOAD_ATTR_WITH_HINT 342 #define _LOAD_ATTR_SLOT 332
#define _LOAD_ATTR_SLOT 343 #define _CHECK_ATTR_CLASS 333
#define _CHECK_ATTR_CLASS 344 #define _LOAD_ATTR_CLASS 334
#define _LOAD_ATTR_CLASS 345
#define _LOAD_ATTR_PROPERTY LOAD_ATTR_PROPERTY #define _LOAD_ATTR_PROPERTY LOAD_ATTR_PROPERTY
#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN #define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN
#define _GUARD_DORV_VALUES 346 #define _GUARD_DORV_VALUES 335
#define _STORE_ATTR_INSTANCE_VALUE 347 #define _STORE_ATTR_INSTANCE_VALUE 336
#define _STORE_ATTR_WITH_HINT STORE_ATTR_WITH_HINT #define _STORE_ATTR_WITH_HINT STORE_ATTR_WITH_HINT
#define _STORE_ATTR_SLOT 348 #define _STORE_ATTR_SLOT 337
#define _SPECIALIZE_COMPARE_OP 349 #define _COMPARE_OP 338
#define _COMPARE_OP 350
#define _COMPARE_OP_FLOAT COMPARE_OP_FLOAT #define _COMPARE_OP_FLOAT COMPARE_OP_FLOAT
#define _COMPARE_OP_INT COMPARE_OP_INT #define _COMPARE_OP_INT COMPARE_OP_INT
#define _COMPARE_OP_STR COMPARE_OP_STR #define _COMPARE_OP_STR COMPARE_OP_STR
@ -159,15 +139,10 @@ extern "C" {
#define _CONTAINS_OP CONTAINS_OP #define _CONTAINS_OP CONTAINS_OP
#define _CHECK_EG_MATCH CHECK_EG_MATCH #define _CHECK_EG_MATCH CHECK_EG_MATCH
#define _CHECK_EXC_MATCH CHECK_EXC_MATCH #define _CHECK_EXC_MATCH CHECK_EXC_MATCH
#define _IMPORT_NAME IMPORT_NAME
#define _IMPORT_FROM IMPORT_FROM
#define _JUMP_FORWARD JUMP_FORWARD
#define _JUMP_BACKWARD JUMP_BACKWARD #define _JUMP_BACKWARD JUMP_BACKWARD
#define _ENTER_EXECUTOR ENTER_EXECUTOR #define _POP_JUMP_IF_FALSE 339
#define _POP_JUMP_IF_FALSE 351 #define _POP_JUMP_IF_TRUE 340
#define _POP_JUMP_IF_TRUE 352 #define _IS_NONE 341
#define _IS_NONE 353
#define _JUMP_BACKWARD_NO_INTERRUPT JUMP_BACKWARD_NO_INTERRUPT
#define _GET_LEN GET_LEN #define _GET_LEN GET_LEN
#define _MATCH_CLASS MATCH_CLASS #define _MATCH_CLASS MATCH_CLASS
#define _MATCH_MAPPING MATCH_MAPPING #define _MATCH_MAPPING MATCH_MAPPING
@ -175,45 +150,43 @@ extern "C" {
#define _MATCH_KEYS MATCH_KEYS #define _MATCH_KEYS MATCH_KEYS
#define _GET_ITER GET_ITER #define _GET_ITER GET_ITER
#define _GET_YIELD_FROM_ITER GET_YIELD_FROM_ITER #define _GET_YIELD_FROM_ITER GET_YIELD_FROM_ITER
#define _SPECIALIZE_FOR_ITER 354 #define _FOR_ITER 342
#define _FOR_ITER 355 #define _FOR_ITER_TIER_TWO 343
#define _FOR_ITER_TIER_TWO 356
#define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER #define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER
#define _ITER_CHECK_LIST 357 #define _ITER_CHECK_LIST 344
#define _ITER_JUMP_LIST 358 #define _ITER_JUMP_LIST 345
#define _GUARD_NOT_EXHAUSTED_LIST 359 #define _GUARD_NOT_EXHAUSTED_LIST 346
#define _ITER_NEXT_LIST 360 #define _ITER_NEXT_LIST 347
#define _ITER_CHECK_TUPLE 361 #define _ITER_CHECK_TUPLE 348
#define _ITER_JUMP_TUPLE 362 #define _ITER_JUMP_TUPLE 349
#define _GUARD_NOT_EXHAUSTED_TUPLE 363 #define _GUARD_NOT_EXHAUSTED_TUPLE 350
#define _ITER_NEXT_TUPLE 364 #define _ITER_NEXT_TUPLE 351
#define _ITER_CHECK_RANGE 365 #define _ITER_CHECK_RANGE 352
#define _ITER_JUMP_RANGE 366 #define _ITER_JUMP_RANGE 353
#define _GUARD_NOT_EXHAUSTED_RANGE 367 #define _GUARD_NOT_EXHAUSTED_RANGE 354
#define _ITER_NEXT_RANGE 368 #define _ITER_NEXT_RANGE 355
#define _FOR_ITER_GEN FOR_ITER_GEN #define _FOR_ITER_GEN FOR_ITER_GEN
#define _BEFORE_ASYNC_WITH BEFORE_ASYNC_WITH #define _BEFORE_ASYNC_WITH BEFORE_ASYNC_WITH
#define _BEFORE_WITH BEFORE_WITH #define _BEFORE_WITH BEFORE_WITH
#define _WITH_EXCEPT_START WITH_EXCEPT_START #define _WITH_EXCEPT_START WITH_EXCEPT_START
#define _PUSH_EXC_INFO PUSH_EXC_INFO #define _PUSH_EXC_INFO PUSH_EXC_INFO
#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 369 #define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 356
#define _GUARD_KEYS_VERSION 370 #define _GUARD_KEYS_VERSION 357
#define _LOAD_ATTR_METHOD_WITH_VALUES 371 #define _LOAD_ATTR_METHOD_WITH_VALUES 358
#define _LOAD_ATTR_METHOD_NO_DICT 372 #define _LOAD_ATTR_METHOD_NO_DICT 359
#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 373 #define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 360
#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 374 #define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 361
#define _CHECK_ATTR_METHOD_LAZY_DICT 375 #define _CHECK_ATTR_METHOD_LAZY_DICT 362
#define _LOAD_ATTR_METHOD_LAZY_DICT 376 #define _LOAD_ATTR_METHOD_LAZY_DICT 363
#define _INSTRUMENTED_CALL INSTRUMENTED_CALL #define _INSTRUMENTED_CALL INSTRUMENTED_CALL
#define _SPECIALIZE_CALL 377 #define _CALL 364
#define _CALL 378 #define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 365
#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 379 #define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 366
#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 380 #define _CHECK_PEP_523 367
#define _CHECK_PEP_523 381 #define _CHECK_FUNCTION_EXACT_ARGS 368
#define _CHECK_FUNCTION_EXACT_ARGS 382 #define _CHECK_STACK_SPACE 369
#define _CHECK_STACK_SPACE 383 #define _INIT_CALL_PY_EXACT_ARGS 370
#define _INIT_CALL_PY_EXACT_ARGS 384 #define _PUSH_FRAME 371
#define _PUSH_FRAME 385
#define _CALL_PY_WITH_DEFAULTS CALL_PY_WITH_DEFAULTS #define _CALL_PY_WITH_DEFAULTS CALL_PY_WITH_DEFAULTS
#define _CALL_TYPE_1 CALL_TYPE_1 #define _CALL_TYPE_1 CALL_TYPE_1
#define _CALL_STR_1 CALL_STR_1 #define _CALL_STR_1 CALL_STR_1
@ -226,7 +199,6 @@ extern "C" {
#define _CALL_BUILTIN_FAST_WITH_KEYWORDS CALL_BUILTIN_FAST_WITH_KEYWORDS #define _CALL_BUILTIN_FAST_WITH_KEYWORDS CALL_BUILTIN_FAST_WITH_KEYWORDS
#define _CALL_LEN CALL_LEN #define _CALL_LEN CALL_LEN
#define _CALL_ISINSTANCE CALL_ISINSTANCE #define _CALL_ISINSTANCE CALL_ISINSTANCE
#define _CALL_LIST_APPEND CALL_LIST_APPEND
#define _CALL_METHOD_DESCRIPTOR_O CALL_METHOD_DESCRIPTOR_O #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_FAST_WITH_KEYWORDS CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS
#define _CALL_METHOD_DESCRIPTOR_NOARGS CALL_METHOD_DESCRIPTOR_NOARGS #define _CALL_METHOD_DESCRIPTOR_NOARGS CALL_METHOD_DESCRIPTOR_NOARGS
@ -237,14 +209,12 @@ extern "C" {
#define _CALL_FUNCTION_EX CALL_FUNCTION_EX #define _CALL_FUNCTION_EX CALL_FUNCTION_EX
#define _MAKE_FUNCTION MAKE_FUNCTION #define _MAKE_FUNCTION MAKE_FUNCTION
#define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE
#define _RETURN_GENERATOR RETURN_GENERATOR
#define _BUILD_SLICE BUILD_SLICE #define _BUILD_SLICE BUILD_SLICE
#define _CONVERT_VALUE CONVERT_VALUE #define _CONVERT_VALUE CONVERT_VALUE
#define _FORMAT_SIMPLE FORMAT_SIMPLE #define _FORMAT_SIMPLE FORMAT_SIMPLE
#define _FORMAT_WITH_SPEC FORMAT_WITH_SPEC #define _FORMAT_WITH_SPEC FORMAT_WITH_SPEC
#define _COPY COPY #define _COPY COPY
#define _SPECIALIZE_BINARY_OP 386 #define _BINARY_OP 372
#define _BINARY_OP 387
#define _SWAP SWAP #define _SWAP SWAP
#define _INSTRUMENTED_INSTRUCTION INSTRUMENTED_INSTRUCTION #define _INSTRUMENTED_INSTRUCTION INSTRUMENTED_INSTRUCTION
#define _INSTRUMENTED_JUMP_FORWARD INSTRUMENTED_JUMP_FORWARD #define _INSTRUMENTED_JUMP_FORWARD INSTRUMENTED_JUMP_FORWARD
@ -253,16 +223,17 @@ extern "C" {
#define _INSTRUMENTED_POP_JUMP_IF_FALSE INSTRUMENTED_POP_JUMP_IF_FALSE #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_NONE INSTRUMENTED_POP_JUMP_IF_NONE
#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE INSTRUMENTED_POP_JUMP_IF_NOT_NONE #define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE INSTRUMENTED_POP_JUMP_IF_NOT_NONE
#define _GUARD_IS_TRUE_POP 388 #define _GUARD_IS_TRUE_POP 373
#define _GUARD_IS_FALSE_POP 389 #define _GUARD_IS_FALSE_POP 374
#define _GUARD_IS_NONE_POP 390 #define _GUARD_IS_NONE_POP 375
#define _GUARD_IS_NOT_NONE_POP 391 #define _GUARD_IS_NOT_NONE_POP 376
#define _JUMP_TO_TOP 392 #define _JUMP_TO_TOP 377
#define _SAVE_RETURN_OFFSET 393 #define _SAVE_RETURN_OFFSET 378
#define _INSERT 394 #define _INSERT 379
#define _CHECK_VALIDITY 395 #define _CHECK_VALIDITY 380
#define MAX_UOP_ID 380
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* !Py_OPCODE_IDS_H */ #endif /* !Py_CORE_UOP_IDS_H */

View file

@ -0,0 +1,403 @@
// This file is generated by Tools/cases_generator/uop_metadata_generator.py
// from:
// Python/bytecodes.c
// Do not edit!
#ifndef Py_CORE_UOP_METADATA_H
#define Py_CORE_UOP_METADATA_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "pycore_uop_ids.h"
extern const uint16_t _PyUop_Flags[MAX_UOP_ID+1];
extern const char * const _PyOpcode_uop_name[MAX_UOP_ID+1];
#ifdef NEED_OPCODE_METADATA
const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_NOP] = 0,
[_RESUME_CHECK] = HAS_DEOPT_FLAG,
[_LOAD_FAST_CHECK] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ERROR_FLAG,
[_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_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,
[_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,
[_POP_TOP] = 0,
[_PUSH_NULL] = 0,
[_END_SEND] = 0,
[_UNARY_NEGATIVE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_UNARY_NOT] = 0,
[_TO_BOOL] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_TO_BOOL_BOOL] = HAS_DEOPT_FLAG,
[_TO_BOOL_INT] = HAS_DEOPT_FLAG,
[_TO_BOOL_LIST] = HAS_DEOPT_FLAG,
[_TO_BOOL_NONE] = HAS_DEOPT_FLAG,
[_TO_BOOL_STR] = HAS_DEOPT_FLAG,
[_TO_BOOL_ALWAYS_TRUE] = HAS_DEOPT_FLAG,
[_UNARY_INVERT] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_GUARD_BOTH_INT] = HAS_DEOPT_FLAG,
[_BINARY_OP_MULTIPLY_INT] = HAS_ERROR_FLAG,
[_BINARY_OP_ADD_INT] = HAS_ERROR_FLAG,
[_BINARY_OP_SUBTRACT_INT] = HAS_ERROR_FLAG,
[_GUARD_BOTH_FLOAT] = HAS_DEOPT_FLAG,
[_BINARY_OP_MULTIPLY_FLOAT] = 0,
[_BINARY_OP_ADD_FLOAT] = 0,
[_BINARY_OP_SUBTRACT_FLOAT] = 0,
[_GUARD_BOTH_UNICODE] = HAS_DEOPT_FLAG,
[_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_BINARY_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_BINARY_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_STORE_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_BINARY_SUBSCR_LIST_INT] = HAS_DEOPT_FLAG,
[_BINARY_SUBSCR_STR_INT] = HAS_DEOPT_FLAG,
[_BINARY_SUBSCR_TUPLE_INT] = HAS_DEOPT_FLAG,
[_BINARY_SUBSCR_DICT] = HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_LIST_APPEND] = HAS_ARG_FLAG | HAS_ERROR_FLAG,
[_SET_ADD] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_STORE_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_STORE_SUBSCR_LIST_INT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG,
[_STORE_SUBSCR_DICT] = HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_DELETE_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_CALL_INTRINSIC_1] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_CALL_INTRINSIC_2] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_POP_FRAME] = HAS_ESCAPES_FLAG,
[_GET_AITER] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_GET_ANEXT] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_GET_AWAITABLE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_POP_EXCEPT] = HAS_ESCAPES_FLAG,
[_LOAD_ASSERTION_ERROR] = 0,
[_LOAD_BUILD_CLASS] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_STORE_NAME] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_DELETE_NAME] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_UNPACK_SEQUENCE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_UNPACK_SEQUENCE_TWO_TUPLE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG,
[_UNPACK_SEQUENCE_TUPLE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG,
[_UNPACK_SEQUENCE_LIST] = HAS_ARG_FLAG | HAS_DEOPT_FLAG,
[_UNPACK_EX] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_STORE_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_DELETE_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_STORE_GLOBAL] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_DELETE_GLOBAL] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_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,
[_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,
[_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,
[_LOAD_FROM_DICT_OR_DEREF] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_LOAD_DEREF] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_STORE_DEREF] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ESCAPES_FLAG,
[_COPY_FREE_VARS] = HAS_ARG_FLAG,
[_BUILD_STRING] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_BUILD_TUPLE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_BUILD_LIST] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_LIST_EXTEND] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_SET_UPDATE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_BUILD_SET] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_BUILD_MAP] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_SETUP_ANNOTATIONS] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_BUILD_CONST_KEY_MAP] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_DICT_UPDATE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_DICT_MERGE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_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,
[_GUARD_TYPE_VERSION] = HAS_DEOPT_FLAG,
[_CHECK_MANAGED_OBJECT_HAS_VALUES] = HAS_DEOPT_FLAG,
[_LOAD_ATTR_INSTANCE_VALUE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG,
[_CHECK_ATTR_MODULE] = HAS_DEOPT_FLAG,
[_LOAD_ATTR_MODULE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG,
[_CHECK_ATTR_WITH_HINT] = HAS_DEOPT_FLAG | HAS_ESCAPES_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,
[_CHECK_ATTR_CLASS] = HAS_DEOPT_FLAG,
[_LOAD_ATTR_CLASS] = HAS_ARG_FLAG,
[_GUARD_DORV_VALUES] = HAS_DEOPT_FLAG,
[_STORE_ATTR_INSTANCE_VALUE] = HAS_ESCAPES_FLAG,
[_STORE_ATTR_SLOT] = HAS_ESCAPES_FLAG,
[_COMPARE_OP] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_COMPARE_OP_FLOAT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG,
[_COMPARE_OP_INT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG,
[_COMPARE_OP_STR] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG,
[_IS_OP] = HAS_ARG_FLAG,
[_CONTAINS_OP] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_CHECK_EG_MATCH] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_CHECK_EXC_MATCH] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_IS_NONE] = 0,
[_GET_LEN] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_MATCH_CLASS] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_MATCH_MAPPING] = 0,
[_MATCH_SEQUENCE] = 0,
[_MATCH_KEYS] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_GET_ITER] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_GET_YIELD_FROM_ITER] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_FOR_ITER_TIER_TWO] = HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_ITER_CHECK_LIST] = HAS_DEOPT_FLAG,
[_GUARD_NOT_EXHAUSTED_LIST] = HAS_DEOPT_FLAG,
[_ITER_NEXT_LIST] = 0,
[_ITER_CHECK_TUPLE] = HAS_DEOPT_FLAG,
[_GUARD_NOT_EXHAUSTED_TUPLE] = HAS_DEOPT_FLAG,
[_ITER_NEXT_TUPLE] = 0,
[_ITER_CHECK_RANGE] = HAS_DEOPT_FLAG,
[_GUARD_NOT_EXHAUSTED_RANGE] = HAS_DEOPT_FLAG,
[_ITER_NEXT_RANGE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_BEFORE_ASYNC_WITH] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_BEFORE_WITH] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_WITH_EXCEPT_START] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_PUSH_EXC_INFO] = 0,
[_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT] = HAS_DEOPT_FLAG,
[_GUARD_KEYS_VERSION] = HAS_DEOPT_FLAG,
[_LOAD_ATTR_METHOD_WITH_VALUES] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
[_LOAD_ATTR_METHOD_NO_DICT] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
[_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = HAS_ARG_FLAG,
[_LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = HAS_ARG_FLAG,
[_CHECK_ATTR_METHOD_LAZY_DICT] = HAS_DEOPT_FLAG,
[_LOAD_ATTR_METHOD_LAZY_DICT] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
[_CHECK_CALL_BOUND_METHOD_EXACT_ARGS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG,
[_INIT_CALL_BOUND_METHOD_EXACT_ARGS] = HAS_ARG_FLAG,
[_CHECK_PEP_523] = HAS_DEOPT_FLAG,
[_CHECK_FUNCTION_EXACT_ARGS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG,
[_CHECK_STACK_SPACE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG,
[_INIT_CALL_PY_EXACT_ARGS] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
[_PUSH_FRAME] = 0,
[_CALL_TYPE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG,
[_CALL_STR_1] = HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_CALL_TUPLE_1] = HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_EXIT_INIT_CHECK] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_CALL_BUILTIN_CLASS] = HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG,
[_CALL_BUILTIN_O] = HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_CALL_BUILTIN_FAST] = HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_CALL_BUILTIN_FAST_WITH_KEYWORDS] = HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_CALL_LEN] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_CALL_ISINSTANCE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_CALL_METHOD_DESCRIPTOR_O] = HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_CALL_METHOD_DESCRIPTOR_NOARGS] = HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_CALL_METHOD_DESCRIPTOR_FAST] = HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_MAKE_FUNCTION] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_SET_FUNCTION_ATTRIBUTE] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
[_BUILD_SLICE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_CONVERT_VALUE] = HAS_ARG_FLAG | HAS_ERROR_FLAG,
[_FORMAT_SIMPLE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_FORMAT_WITH_SPEC] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_COPY] = HAS_ARG_FLAG,
[_BINARY_OP] = HAS_ARG_FLAG | HAS_ERROR_FLAG,
[_SWAP] = HAS_ARG_FLAG,
[_GUARD_IS_TRUE_POP] = HAS_DEOPT_FLAG,
[_GUARD_IS_FALSE_POP] = HAS_DEOPT_FLAG,
[_GUARD_IS_NONE_POP] = HAS_DEOPT_FLAG,
[_GUARD_IS_NOT_NONE_POP] = HAS_DEOPT_FLAG,
[_JUMP_TO_TOP] = HAS_EVAL_BREAK_FLAG,
[_SET_IP] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
[_SAVE_RETURN_OFFSET] = HAS_ARG_FLAG,
[_EXIT_TRACE] = HAS_DEOPT_FLAG,
[_INSERT] = HAS_ARG_FLAG,
[_CHECK_VALIDITY] = HAS_DEOPT_FLAG,
};
const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = {
[_BEFORE_ASYNC_WITH] = "_BEFORE_ASYNC_WITH",
[_BEFORE_WITH] = "_BEFORE_WITH",
[_BINARY_OP] = "_BINARY_OP",
[_BINARY_OP_ADD_FLOAT] = "_BINARY_OP_ADD_FLOAT",
[_BINARY_OP_ADD_INT] = "_BINARY_OP_ADD_INT",
[_BINARY_OP_ADD_UNICODE] = "_BINARY_OP_ADD_UNICODE",
[_BINARY_OP_MULTIPLY_FLOAT] = "_BINARY_OP_MULTIPLY_FLOAT",
[_BINARY_OP_MULTIPLY_INT] = "_BINARY_OP_MULTIPLY_INT",
[_BINARY_OP_SUBTRACT_FLOAT] = "_BINARY_OP_SUBTRACT_FLOAT",
[_BINARY_OP_SUBTRACT_INT] = "_BINARY_OP_SUBTRACT_INT",
[_BINARY_SLICE] = "_BINARY_SLICE",
[_BINARY_SUBSCR] = "_BINARY_SUBSCR",
[_BINARY_SUBSCR_DICT] = "_BINARY_SUBSCR_DICT",
[_BINARY_SUBSCR_LIST_INT] = "_BINARY_SUBSCR_LIST_INT",
[_BINARY_SUBSCR_STR_INT] = "_BINARY_SUBSCR_STR_INT",
[_BINARY_SUBSCR_TUPLE_INT] = "_BINARY_SUBSCR_TUPLE_INT",
[_BUILD_CONST_KEY_MAP] = "_BUILD_CONST_KEY_MAP",
[_BUILD_LIST] = "_BUILD_LIST",
[_BUILD_MAP] = "_BUILD_MAP",
[_BUILD_SET] = "_BUILD_SET",
[_BUILD_SLICE] = "_BUILD_SLICE",
[_BUILD_STRING] = "_BUILD_STRING",
[_BUILD_TUPLE] = "_BUILD_TUPLE",
[_CALL_BUILTIN_CLASS] = "_CALL_BUILTIN_CLASS",
[_CALL_BUILTIN_FAST] = "_CALL_BUILTIN_FAST",
[_CALL_BUILTIN_FAST_WITH_KEYWORDS] = "_CALL_BUILTIN_FAST_WITH_KEYWORDS",
[_CALL_BUILTIN_O] = "_CALL_BUILTIN_O",
[_CALL_INTRINSIC_1] = "_CALL_INTRINSIC_1",
[_CALL_INTRINSIC_2] = "_CALL_INTRINSIC_2",
[_CALL_ISINSTANCE] = "_CALL_ISINSTANCE",
[_CALL_LEN] = "_CALL_LEN",
[_CALL_METHOD_DESCRIPTOR_FAST] = "_CALL_METHOD_DESCRIPTOR_FAST",
[_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS",
[_CALL_METHOD_DESCRIPTOR_NOARGS] = "_CALL_METHOD_DESCRIPTOR_NOARGS",
[_CALL_METHOD_DESCRIPTOR_O] = "_CALL_METHOD_DESCRIPTOR_O",
[_CALL_STR_1] = "_CALL_STR_1",
[_CALL_TUPLE_1] = "_CALL_TUPLE_1",
[_CALL_TYPE_1] = "_CALL_TYPE_1",
[_CHECK_ATTR_CLASS] = "_CHECK_ATTR_CLASS",
[_CHECK_ATTR_METHOD_LAZY_DICT] = "_CHECK_ATTR_METHOD_LAZY_DICT",
[_CHECK_ATTR_MODULE] = "_CHECK_ATTR_MODULE",
[_CHECK_ATTR_WITH_HINT] = "_CHECK_ATTR_WITH_HINT",
[_CHECK_CALL_BOUND_METHOD_EXACT_ARGS] = "_CHECK_CALL_BOUND_METHOD_EXACT_ARGS",
[_CHECK_EG_MATCH] = "_CHECK_EG_MATCH",
[_CHECK_EXC_MATCH] = "_CHECK_EXC_MATCH",
[_CHECK_FUNCTION_EXACT_ARGS] = "_CHECK_FUNCTION_EXACT_ARGS",
[_CHECK_MANAGED_OBJECT_HAS_VALUES] = "_CHECK_MANAGED_OBJECT_HAS_VALUES",
[_CHECK_PEP_523] = "_CHECK_PEP_523",
[_CHECK_STACK_SPACE] = "_CHECK_STACK_SPACE",
[_CHECK_VALIDITY] = "_CHECK_VALIDITY",
[_COMPARE_OP] = "_COMPARE_OP",
[_COMPARE_OP_FLOAT] = "_COMPARE_OP_FLOAT",
[_COMPARE_OP_INT] = "_COMPARE_OP_INT",
[_COMPARE_OP_STR] = "_COMPARE_OP_STR",
[_CONTAINS_OP] = "_CONTAINS_OP",
[_CONVERT_VALUE] = "_CONVERT_VALUE",
[_COPY] = "_COPY",
[_COPY_FREE_VARS] = "_COPY_FREE_VARS",
[_DELETE_ATTR] = "_DELETE_ATTR",
[_DELETE_DEREF] = "_DELETE_DEREF",
[_DELETE_FAST] = "_DELETE_FAST",
[_DELETE_GLOBAL] = "_DELETE_GLOBAL",
[_DELETE_NAME] = "_DELETE_NAME",
[_DELETE_SUBSCR] = "_DELETE_SUBSCR",
[_DICT_MERGE] = "_DICT_MERGE",
[_DICT_UPDATE] = "_DICT_UPDATE",
[_END_SEND] = "_END_SEND",
[_EXIT_INIT_CHECK] = "_EXIT_INIT_CHECK",
[_EXIT_TRACE] = "_EXIT_TRACE",
[_FORMAT_SIMPLE] = "_FORMAT_SIMPLE",
[_FORMAT_WITH_SPEC] = "_FORMAT_WITH_SPEC",
[_FOR_ITER_TIER_TWO] = "_FOR_ITER_TIER_TWO",
[_GET_AITER] = "_GET_AITER",
[_GET_ANEXT] = "_GET_ANEXT",
[_GET_AWAITABLE] = "_GET_AWAITABLE",
[_GET_ITER] = "_GET_ITER",
[_GET_LEN] = "_GET_LEN",
[_GET_YIELD_FROM_ITER] = "_GET_YIELD_FROM_ITER",
[_GUARD_BOTH_FLOAT] = "_GUARD_BOTH_FLOAT",
[_GUARD_BOTH_INT] = "_GUARD_BOTH_INT",
[_GUARD_BOTH_UNICODE] = "_GUARD_BOTH_UNICODE",
[_GUARD_BUILTINS_VERSION] = "_GUARD_BUILTINS_VERSION",
[_GUARD_DORV_VALUES] = "_GUARD_DORV_VALUES",
[_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT] = "_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT",
[_GUARD_GLOBALS_VERSION] = "_GUARD_GLOBALS_VERSION",
[_GUARD_IS_FALSE_POP] = "_GUARD_IS_FALSE_POP",
[_GUARD_IS_NONE_POP] = "_GUARD_IS_NONE_POP",
[_GUARD_IS_NOT_NONE_POP] = "_GUARD_IS_NOT_NONE_POP",
[_GUARD_IS_TRUE_POP] = "_GUARD_IS_TRUE_POP",
[_GUARD_KEYS_VERSION] = "_GUARD_KEYS_VERSION",
[_GUARD_NOT_EXHAUSTED_LIST] = "_GUARD_NOT_EXHAUSTED_LIST",
[_GUARD_NOT_EXHAUSTED_RANGE] = "_GUARD_NOT_EXHAUSTED_RANGE",
[_GUARD_NOT_EXHAUSTED_TUPLE] = "_GUARD_NOT_EXHAUSTED_TUPLE",
[_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",
[_INSERT] = "_INSERT",
[_IS_NONE] = "_IS_NONE",
[_IS_OP] = "_IS_OP",
[_ITER_CHECK_LIST] = "_ITER_CHECK_LIST",
[_ITER_CHECK_RANGE] = "_ITER_CHECK_RANGE",
[_ITER_CHECK_TUPLE] = "_ITER_CHECK_TUPLE",
[_ITER_NEXT_LIST] = "_ITER_NEXT_LIST",
[_ITER_NEXT_RANGE] = "_ITER_NEXT_RANGE",
[_ITER_NEXT_TUPLE] = "_ITER_NEXT_TUPLE",
[_JUMP_TO_TOP] = "_JUMP_TO_TOP",
[_LIST_APPEND] = "_LIST_APPEND",
[_LIST_EXTEND] = "_LIST_EXTEND",
[_LOAD_ASSERTION_ERROR] = "_LOAD_ASSERTION_ERROR",
[_LOAD_ATTR] = "_LOAD_ATTR",
[_LOAD_ATTR_CLASS] = "_LOAD_ATTR_CLASS",
[_LOAD_ATTR_INSTANCE_VALUE] = "_LOAD_ATTR_INSTANCE_VALUE",
[_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_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_WITH_HINT] = "_LOAD_ATTR_WITH_HINT",
[_LOAD_BUILD_CLASS] = "_LOAD_BUILD_CLASS",
[_LOAD_CONST] = "_LOAD_CONST",
[_LOAD_DEREF] = "_LOAD_DEREF",
[_LOAD_FAST] = "_LOAD_FAST",
[_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_BUILTINS] = "_LOAD_GLOBAL_BUILTINS",
[_LOAD_GLOBAL_MODULE] = "_LOAD_GLOBAL_MODULE",
[_LOAD_LOCALS] = "_LOAD_LOCALS",
[_LOAD_NAME] = "_LOAD_NAME",
[_LOAD_SUPER_ATTR_ATTR] = "_LOAD_SUPER_ATTR_ATTR",
[_LOAD_SUPER_ATTR_METHOD] = "_LOAD_SUPER_ATTR_METHOD",
[_MAKE_CELL] = "_MAKE_CELL",
[_MAKE_FUNCTION] = "_MAKE_FUNCTION",
[_MAP_ADD] = "_MAP_ADD",
[_MATCH_CLASS] = "_MATCH_CLASS",
[_MATCH_KEYS] = "_MATCH_KEYS",
[_MATCH_MAPPING] = "_MATCH_MAPPING",
[_MATCH_SEQUENCE] = "_MATCH_SEQUENCE",
[_NOP] = "_NOP",
[_POP_EXCEPT] = "_POP_EXCEPT",
[_POP_FRAME] = "_POP_FRAME",
[_POP_TOP] = "_POP_TOP",
[_PUSH_EXC_INFO] = "_PUSH_EXC_INFO",
[_PUSH_FRAME] = "_PUSH_FRAME",
[_PUSH_NULL] = "_PUSH_NULL",
[_RESUME_CHECK] = "_RESUME_CHECK",
[_SAVE_RETURN_OFFSET] = "_SAVE_RETURN_OFFSET",
[_SETUP_ANNOTATIONS] = "_SETUP_ANNOTATIONS",
[_SET_ADD] = "_SET_ADD",
[_SET_FUNCTION_ATTRIBUTE] = "_SET_FUNCTION_ATTRIBUTE",
[_SET_IP] = "_SET_IP",
[_SET_UPDATE] = "_SET_UPDATE",
[_STORE_ATTR] = "_STORE_ATTR",
[_STORE_ATTR_INSTANCE_VALUE] = "_STORE_ATTR_INSTANCE_VALUE",
[_STORE_ATTR_SLOT] = "_STORE_ATTR_SLOT",
[_STORE_DEREF] = "_STORE_DEREF",
[_STORE_FAST] = "_STORE_FAST",
[_STORE_FAST_LOAD_FAST] = "_STORE_FAST_LOAD_FAST",
[_STORE_FAST_STORE_FAST] = "_STORE_FAST_STORE_FAST",
[_STORE_GLOBAL] = "_STORE_GLOBAL",
[_STORE_NAME] = "_STORE_NAME",
[_STORE_SLICE] = "_STORE_SLICE",
[_STORE_SUBSCR] = "_STORE_SUBSCR",
[_STORE_SUBSCR_DICT] = "_STORE_SUBSCR_DICT",
[_STORE_SUBSCR_LIST_INT] = "_STORE_SUBSCR_LIST_INT",
[_SWAP] = "_SWAP",
[_TO_BOOL] = "_TO_BOOL",
[_TO_BOOL_ALWAYS_TRUE] = "_TO_BOOL_ALWAYS_TRUE",
[_TO_BOOL_BOOL] = "_TO_BOOL_BOOL",
[_TO_BOOL_INT] = "_TO_BOOL_INT",
[_TO_BOOL_LIST] = "_TO_BOOL_LIST",
[_TO_BOOL_NONE] = "_TO_BOOL_NONE",
[_TO_BOOL_STR] = "_TO_BOOL_STR",
[_UNARY_INVERT] = "_UNARY_INVERT",
[_UNARY_NEGATIVE] = "_UNARY_NEGATIVE",
[_UNARY_NOT] = "_UNARY_NOT",
[_UNPACK_EX] = "_UNPACK_EX",
[_UNPACK_SEQUENCE] = "_UNPACK_SEQUENCE",
[_UNPACK_SEQUENCE_LIST] = "_UNPACK_SEQUENCE_LIST",
[_UNPACK_SEQUENCE_TUPLE] = "_UNPACK_SEQUENCE_TUPLE",
[_UNPACK_SEQUENCE_TWO_TUPLE] = "_UNPACK_SEQUENCE_TWO_TUPLE",
[_WITH_EXCEPT_START] = "_WITH_EXCEPT_START",
};
#endif // NEED_OPCODE_METADATA
#ifdef __cplusplus
}
#endif
#endif /* !Py_CORE_UOP_METADATA_H */

2
Include/opcode_ids.h generated
View file

@ -231,7 +231,7 @@ extern "C" {
#define SETUP_WITH 266 #define SETUP_WITH 266
#define STORE_FAST_MAYBE_NULL 267 #define STORE_FAST_MAYBE_NULL 267
#define HAVE_ARGUMENT 45 #define HAVE_ARGUMENT 44
#define MIN_INSTRUMENTED_OPCODE 236 #define MIN_INSTRUMENTED_OPCODE 236
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -1,8 +1,7 @@
# This file is generated by Tools/cases_generator/generate_cases.py # This file is generated by Tools/cases_generator/py_metadata_generator.py
# from: # from:
# Python/bytecodes.c # Python/bytecodes.c
# Do not edit! # Do not edit!
_specializations = { _specializations = {
"RESUME": [ "RESUME": [
"RESUME_CHECK", "RESUME_CHECK",
@ -23,6 +22,7 @@ _specializations = {
"BINARY_OP_ADD_FLOAT", "BINARY_OP_ADD_FLOAT",
"BINARY_OP_SUBTRACT_FLOAT", "BINARY_OP_SUBTRACT_FLOAT",
"BINARY_OP_ADD_UNICODE", "BINARY_OP_ADD_UNICODE",
"BINARY_OP_INPLACE_ADD_UNICODE",
], ],
"BINARY_SUBSCR": [ "BINARY_SUBSCR": [
"BINARY_SUBSCR_DICT", "BINARY_SUBSCR_DICT",
@ -103,14 +103,11 @@ _specializations = {
], ],
} }
# An irregular case:
_specializations["BINARY_OP"].append("BINARY_OP_INPLACE_ADD_UNICODE")
_specialized_opmap = { _specialized_opmap = {
'BINARY_OP_INPLACE_ADD_UNICODE': 3,
'BINARY_OP_ADD_FLOAT': 150, 'BINARY_OP_ADD_FLOAT': 150,
'BINARY_OP_ADD_INT': 151, 'BINARY_OP_ADD_INT': 151,
'BINARY_OP_ADD_UNICODE': 152, 'BINARY_OP_ADD_UNICODE': 152,
'BINARY_OP_INPLACE_ADD_UNICODE': 3,
'BINARY_OP_MULTIPLY_FLOAT': 153, 'BINARY_OP_MULTIPLY_FLOAT': 153,
'BINARY_OP_MULTIPLY_INT': 154, 'BINARY_OP_MULTIPLY_INT': 154,
'BINARY_OP_SUBTRACT_FLOAT': 155, 'BINARY_OP_SUBTRACT_FLOAT': 155,
@ -181,6 +178,9 @@ _specialized_opmap = {
opmap = { opmap = {
'CACHE': 0, 'CACHE': 0,
'RESERVED': 17,
'RESUME': 149,
'INSTRUMENTED_LINE': 254,
'BEFORE_ASYNC_WITH': 1, 'BEFORE_ASYNC_WITH': 1,
'BEFORE_WITH': 2, 'BEFORE_WITH': 2,
'BINARY_SLICE': 4, 'BINARY_SLICE': 4,
@ -196,7 +196,6 @@ opmap = {
'FORMAT_SIMPLE': 14, 'FORMAT_SIMPLE': 14,
'FORMAT_WITH_SPEC': 15, 'FORMAT_WITH_SPEC': 15,
'GET_AITER': 16, 'GET_AITER': 16,
'RESERVED': 17,
'GET_ANEXT': 18, 'GET_ANEXT': 18,
'GET_ITER': 19, 'GET_ITER': 19,
'GET_LEN': 20, 'GET_LEN': 20,
@ -298,7 +297,6 @@ opmap = {
'UNPACK_EX': 116, 'UNPACK_EX': 116,
'UNPACK_SEQUENCE': 117, 'UNPACK_SEQUENCE': 117,
'YIELD_VALUE': 118, 'YIELD_VALUE': 118,
'RESUME': 149,
'INSTRUMENTED_RESUME': 236, 'INSTRUMENTED_RESUME': 236,
'INSTRUMENTED_END_FOR': 237, 'INSTRUMENTED_END_FOR': 237,
'INSTRUMENTED_END_SEND': 238, 'INSTRUMENTED_END_SEND': 238,
@ -317,7 +315,6 @@ opmap = {
'INSTRUMENTED_POP_JUMP_IF_FALSE': 251, 'INSTRUMENTED_POP_JUMP_IF_FALSE': 251,
'INSTRUMENTED_POP_JUMP_IF_NONE': 252, 'INSTRUMENTED_POP_JUMP_IF_NONE': 252,
'INSTRUMENTED_POP_JUMP_IF_NOT_NONE': 253, 'INSTRUMENTED_POP_JUMP_IF_NOT_NONE': 253,
'INSTRUMENTED_LINE': 254,
'JUMP': 256, 'JUMP': 256,
'JUMP_NO_INTERRUPT': 257, 'JUMP_NO_INTERRUPT': 257,
'LOAD_CLOSURE': 258, 'LOAD_CLOSURE': 258,
@ -331,5 +328,6 @@ opmap = {
'SETUP_WITH': 266, 'SETUP_WITH': 266,
'STORE_FAST_MAYBE_NULL': 267, 'STORE_FAST_MAYBE_NULL': 267,
} }
HAVE_ARGUMENT = 44
MIN_INSTRUMENTED_OPCODE = 236 MIN_INSTRUMENTED_OPCODE = 236
HAVE_ARGUMENT = 45

View file

@ -176,6 +176,7 @@ class TestExecutorInvalidation(unittest.TestCase):
with temporary_optimizer(opt): with temporary_optimizer(opt):
f() f()
exe = get_first_executor(f) exe = get_first_executor(f)
self.assertIsNotNone(exe)
self.assertTrue(exe.is_valid()) self.assertTrue(exe.is_valid())
_testinternalcapi.invalidate_executors(f.__code__) _testinternalcapi.invalidate_executors(f.__code__)
self.assertFalse(exe.is_valid()) self.assertFalse(exe.is_valid())
@ -196,7 +197,7 @@ class TestUops(unittest.TestCase):
self.assertIsNotNone(ex) self.assertIsNotNone(ex)
uops = {opname for opname, _, _ in ex} uops = {opname for opname, _, _ in ex}
self.assertIn("_SET_IP", uops) self.assertIn("_SET_IP", uops)
self.assertIn("LOAD_FAST", uops) self.assertIn("_LOAD_FAST", uops)
def test_extended_arg(self): def test_extended_arg(self):
"Check EXTENDED_ARG handling in superblock creation" "Check EXTENDED_ARG handling in superblock creation"
@ -243,7 +244,7 @@ class TestUops(unittest.TestCase):
ex = get_first_executor(many_vars) ex = get_first_executor(many_vars)
self.assertIsNotNone(ex) self.assertIsNotNone(ex)
self.assertIn(("LOAD_FAST", 259, 0), list(ex)) self.assertIn(("_LOAD_FAST", 259, 0), list(ex))
def test_unspecialized_unpack(self): def test_unspecialized_unpack(self):
# An example of an unspecialized opcode # An example of an unspecialized opcode

View file

@ -1588,23 +1588,28 @@ regen-cases:
$(srcdir)/Tools/cases_generator/generate_cases.py \ $(srcdir)/Tools/cases_generator/generate_cases.py \
$(CASESFLAG) \ $(CASESFLAG) \
-t $(srcdir)/Python/opcode_targets.h.new \ -t $(srcdir)/Python/opcode_targets.h.new \
-m $(srcdir)/Include/internal/pycore_opcode_metadata.h.new \
-p $(srcdir)/Lib/_opcode_metadata.py.new \
-a $(srcdir)/Python/abstract_interp_cases.c.h.new \ -a $(srcdir)/Python/abstract_interp_cases.c.h.new \
$(srcdir)/Python/bytecodes.c $(srcdir)/Python/bytecodes.c
$(PYTHON_FOR_REGEN) \ $(PYTHON_FOR_REGEN) $(srcdir)/Tools/cases_generator/opcode_id_generator.py \
$(srcdir)/Tools/cases_generator/opcode_id_generator.py -o $(srcdir)/Include/opcode_ids.h.new $(srcdir)/Python/bytecodes.c -o $(srcdir)/Include/opcode_ids.h.new $(srcdir)/Python/bytecodes.c
$(PYTHON_FOR_REGEN) \ $(PYTHON_FOR_REGEN) $(srcdir)/Tools/cases_generator/uop_id_generator.py \
$(srcdir)/Tools/cases_generator/uop_id_generator.py -o $(srcdir)/Include/internal/pycore_uop_ids.h.new $(srcdir)/Python/bytecodes.c -o $(srcdir)/Include/internal/pycore_uop_ids.h.new $(srcdir)/Python/bytecodes.c
$(PYTHON_FOR_REGEN) \ $(PYTHON_FOR_REGEN) $(srcdir)/Tools/cases_generator/py_metadata_generator.py \
$(srcdir)/Tools/cases_generator/tier1_generator.py -o $(srcdir)/Python/generated_cases.c.h.new $(srcdir)/Python/bytecodes.c -o $(srcdir)/Lib/_opcode_metadata.py.new $(srcdir)/Python/bytecodes.c
$(PYTHON_FOR_REGEN) \ $(PYTHON_FOR_REGEN) $(srcdir)/Tools/cases_generator/tier1_generator.py \
$(srcdir)/Tools/cases_generator/tier2_generator.py -o $(srcdir)/Python/executor_cases.c.h.new $(srcdir)/Python/bytecodes.c -o $(srcdir)/Python/generated_cases.c.h.new $(srcdir)/Python/bytecodes.c
$(PYTHON_FOR_REGEN) $(srcdir)/Tools/cases_generator/tier2_generator.py \
-o $(srcdir)/Python/executor_cases.c.h.new $(srcdir)/Python/bytecodes.c
$(PYTHON_FOR_REGEN) $(srcdir)/Tools/cases_generator/opcode_metadata_generator.py \
-o $(srcdir)/Include/internal/pycore_opcode_metadata.h.new $(srcdir)/Python/bytecodes.c
$(PYTHON_FOR_REGEN) $(srcdir)/Tools/cases_generator/uop_metadata_generator.py -o \
$(srcdir)/Include/internal/pycore_uop_metadata.h.new $(srcdir)/Python/bytecodes.c
$(UPDATE_FILE) $(srcdir)/Python/generated_cases.c.h $(srcdir)/Python/generated_cases.c.h.new $(UPDATE_FILE) $(srcdir)/Python/generated_cases.c.h $(srcdir)/Python/generated_cases.c.h.new
$(UPDATE_FILE) $(srcdir)/Include/opcode_ids.h $(srcdir)/Include/opcode_ids.h.new $(UPDATE_FILE) $(srcdir)/Include/opcode_ids.h $(srcdir)/Include/opcode_ids.h.new
$(UPDATE_FILE) $(srcdir)/Include/internal/pycore_uop_ids.h $(srcdir)/Include/internal/pycore_uop_ids.h.new $(UPDATE_FILE) $(srcdir)/Include/internal/pycore_uop_ids.h $(srcdir)/Include/internal/pycore_uop_ids.h.new
$(UPDATE_FILE) $(srcdir)/Python/opcode_targets.h $(srcdir)/Python/opcode_targets.h.new $(UPDATE_FILE) $(srcdir)/Python/opcode_targets.h $(srcdir)/Python/opcode_targets.h.new
$(UPDATE_FILE) $(srcdir)/Include/internal/pycore_opcode_metadata.h $(srcdir)/Include/internal/pycore_opcode_metadata.h.new $(UPDATE_FILE) $(srcdir)/Include/internal/pycore_opcode_metadata.h $(srcdir)/Include/internal/pycore_opcode_metadata.h.new
$(UPDATE_FILE) $(srcdir)/Include/internal/pycore_uop_metadata.h $(srcdir)/Include/internal/pycore_uop_metadata.h.new
$(UPDATE_FILE) $(srcdir)/Python/executor_cases.c.h $(srcdir)/Python/executor_cases.c.h.new $(UPDATE_FILE) $(srcdir)/Python/executor_cases.c.h $(srcdir)/Python/executor_cases.c.h.new
$(UPDATE_FILE) $(srcdir)/Python/abstract_interp_cases.c.h $(srcdir)/Python/abstract_interp_cases.c.h.new $(UPDATE_FILE) $(srcdir)/Python/abstract_interp_cases.c.h $(srcdir)/Python/abstract_interp_cases.c.h.new
$(UPDATE_FILE) $(srcdir)/Lib/_opcode_metadata.py $(srcdir)/Lib/_opcode_metadata.py.new $(UPDATE_FILE) $(srcdir)/Lib/_opcode_metadata.py $(srcdir)/Lib/_opcode_metadata.py.new

View file

@ -4,7 +4,7 @@
#include "pycore_code.h" // write_location_entry_start() #include "pycore_code.h" // write_location_entry_start()
#include "pycore_compile.h" #include "pycore_compile.h"
#include "pycore_opcode_utils.h" // IS_BACKWARDS_JUMP_OPCODE #include "pycore_opcode_utils.h" // IS_BACKWARDS_JUMP_OPCODE
#include "pycore_opcode_metadata.h" // IS_PSEUDO_INSTR, _PyOpcode_Caches #include "pycore_opcode_metadata.h" // is_pseudo_target, _PyOpcode_Caches
#define DEFAULT_CODE_SIZE 128 #define DEFAULT_CODE_SIZE 128
@ -710,13 +710,13 @@ resolve_unconditional_jumps(instr_sequence *instrs)
bool is_forward = (instr->i_oparg > i); bool is_forward = (instr->i_oparg > i);
switch(instr->i_opcode) { switch(instr->i_opcode) {
case JUMP: case JUMP:
assert(SAME_OPCODE_METADATA(JUMP, JUMP_FORWARD)); assert(is_pseudo_target(JUMP, JUMP_FORWARD));
assert(SAME_OPCODE_METADATA(JUMP, JUMP_BACKWARD)); assert(is_pseudo_target(JUMP, JUMP_BACKWARD));
instr->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD; instr->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD;
break; break;
case JUMP_NO_INTERRUPT: case JUMP_NO_INTERRUPT:
assert(SAME_OPCODE_METADATA(JUMP_NO_INTERRUPT, JUMP_FORWARD)); assert(is_pseudo_target(JUMP_NO_INTERRUPT, JUMP_FORWARD));
assert(SAME_OPCODE_METADATA(JUMP_NO_INTERRUPT, JUMP_BACKWARD_NO_INTERRUPT)); assert(is_pseudo_target(JUMP_NO_INTERRUPT, JUMP_BACKWARD_NO_INTERRUPT));
instr->i_opcode = is_forward ? instr->i_opcode = is_forward ?
JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT; JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT;
break; break;

View file

@ -330,14 +330,14 @@ dummy_func(
#endif /* ENABLE_SPECIALIZATION */ #endif /* ENABLE_SPECIALIZATION */
} }
op(_TO_BOOL, (unused/2, value -- res)) { op(_TO_BOOL, (value -- res)) {
int err = PyObject_IsTrue(value); int err = PyObject_IsTrue(value);
DECREF_INPUTS(); DECREF_INPUTS();
ERROR_IF(err < 0, error); ERROR_IF(err < 0, error);
res = err ? Py_True : Py_False; res = err ? Py_True : Py_False;
} }
macro(TO_BOOL) = _SPECIALIZE_TO_BOOL + _TO_BOOL; macro(TO_BOOL) = _SPECIALIZE_TO_BOOL + unused/2 + _TO_BOOL;
inst(TO_BOOL_BOOL, (unused/1, unused/2, value -- value)) { inst(TO_BOOL_BOOL, (unused/1, unused/2, value -- value)) {
DEOPT_IF(!PyBool_Check(value)); DEOPT_IF(!PyBool_Check(value));
@ -416,7 +416,7 @@ dummy_func(
DEOPT_IF(!PyLong_CheckExact(right)); DEOPT_IF(!PyLong_CheckExact(right));
} }
op(_BINARY_OP_MULTIPLY_INT, (unused/1, left, right -- res)) { op(_BINARY_OP_MULTIPLY_INT, (left, right -- res)) {
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right);
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
@ -424,7 +424,7 @@ dummy_func(
ERROR_IF(res == NULL, error); ERROR_IF(res == NULL, error);
} }
op(_BINARY_OP_ADD_INT, (unused/1, left, right -- res)) { op(_BINARY_OP_ADD_INT, (left, right -- res)) {
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right);
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
@ -432,7 +432,7 @@ dummy_func(
ERROR_IF(res == NULL, error); ERROR_IF(res == NULL, error);
} }
op(_BINARY_OP_SUBTRACT_INT, (unused/1, left, right -- res)) { op(_BINARY_OP_SUBTRACT_INT, (left, right -- res)) {
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right);
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
@ -441,18 +441,18 @@ dummy_func(
} }
macro(BINARY_OP_MULTIPLY_INT) = macro(BINARY_OP_MULTIPLY_INT) =
_GUARD_BOTH_INT + _BINARY_OP_MULTIPLY_INT; _GUARD_BOTH_INT + unused/1 + _BINARY_OP_MULTIPLY_INT;
macro(BINARY_OP_ADD_INT) = macro(BINARY_OP_ADD_INT) =
_GUARD_BOTH_INT + _BINARY_OP_ADD_INT; _GUARD_BOTH_INT + unused/1 + _BINARY_OP_ADD_INT;
macro(BINARY_OP_SUBTRACT_INT) = macro(BINARY_OP_SUBTRACT_INT) =
_GUARD_BOTH_INT + _BINARY_OP_SUBTRACT_INT; _GUARD_BOTH_INT + unused/1 + _BINARY_OP_SUBTRACT_INT;
op(_GUARD_BOTH_FLOAT, (left, right -- left, right)) { op(_GUARD_BOTH_FLOAT, (left, right -- left, right)) {
DEOPT_IF(!PyFloat_CheckExact(left)); DEOPT_IF(!PyFloat_CheckExact(left));
DEOPT_IF(!PyFloat_CheckExact(right)); DEOPT_IF(!PyFloat_CheckExact(right));
} }
op(_BINARY_OP_MULTIPLY_FLOAT, (unused/1, left, right -- res)) { op(_BINARY_OP_MULTIPLY_FLOAT, (left, right -- res)) {
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
double dres = double dres =
((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)left)->ob_fval *
@ -460,7 +460,7 @@ dummy_func(
DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res);
} }
op(_BINARY_OP_ADD_FLOAT, (unused/1, left, right -- res)) { op(_BINARY_OP_ADD_FLOAT, (left, right -- res)) {
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
double dres = double dres =
((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)left)->ob_fval +
@ -468,7 +468,7 @@ dummy_func(
DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res);
} }
op(_BINARY_OP_SUBTRACT_FLOAT, (unused/1, left, right -- res)) { op(_BINARY_OP_SUBTRACT_FLOAT, (left, right -- res)) {
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
double dres = double dres =
((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)left)->ob_fval -
@ -477,18 +477,18 @@ dummy_func(
} }
macro(BINARY_OP_MULTIPLY_FLOAT) = macro(BINARY_OP_MULTIPLY_FLOAT) =
_GUARD_BOTH_FLOAT + _BINARY_OP_MULTIPLY_FLOAT; _GUARD_BOTH_FLOAT + unused/1 + _BINARY_OP_MULTIPLY_FLOAT;
macro(BINARY_OP_ADD_FLOAT) = macro(BINARY_OP_ADD_FLOAT) =
_GUARD_BOTH_FLOAT + _BINARY_OP_ADD_FLOAT; _GUARD_BOTH_FLOAT + unused/1 + _BINARY_OP_ADD_FLOAT;
macro(BINARY_OP_SUBTRACT_FLOAT) = macro(BINARY_OP_SUBTRACT_FLOAT) =
_GUARD_BOTH_FLOAT + _BINARY_OP_SUBTRACT_FLOAT; _GUARD_BOTH_FLOAT + unused/1 + _BINARY_OP_SUBTRACT_FLOAT;
op(_GUARD_BOTH_UNICODE, (left, right -- left, right)) { op(_GUARD_BOTH_UNICODE, (left, right -- left, right)) {
DEOPT_IF(!PyUnicode_CheckExact(left)); DEOPT_IF(!PyUnicode_CheckExact(left));
DEOPT_IF(!PyUnicode_CheckExact(right)); DEOPT_IF(!PyUnicode_CheckExact(right));
} }
op(_BINARY_OP_ADD_UNICODE, (unused/1, left, right -- res)) { op(_BINARY_OP_ADD_UNICODE, (left, right -- res)) {
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
res = PyUnicode_Concat(left, right); res = PyUnicode_Concat(left, right);
_Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc);
@ -497,7 +497,7 @@ dummy_func(
} }
macro(BINARY_OP_ADD_UNICODE) = macro(BINARY_OP_ADD_UNICODE) =
_GUARD_BOTH_UNICODE + _BINARY_OP_ADD_UNICODE; _GUARD_BOTH_UNICODE + unused/1 + _BINARY_OP_ADD_UNICODE;
// This is a subtle one. It's a super-instruction for // This is a subtle one. It's a super-instruction for
// BINARY_OP_ADD_UNICODE followed by STORE_FAST // BINARY_OP_ADD_UNICODE followed by STORE_FAST
@ -505,7 +505,7 @@ dummy_func(
// So the inputs are the same as for all BINARY_OP // So the inputs are the same as for all BINARY_OP
// specializations, but there is no output. // specializations, but there is no output.
// At the end we just skip over the STORE_FAST. // At the end we just skip over the STORE_FAST.
op(_BINARY_OP_INPLACE_ADD_UNICODE, (unused/1, left, right --)) { op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right --)) {
TIER_ONE_ONLY TIER_ONE_ONLY
assert(next_instr->op.code == STORE_FAST); assert(next_instr->op.code == STORE_FAST);
PyObject **target_local = &GETLOCAL(next_instr->op.arg); PyObject **target_local = &GETLOCAL(next_instr->op.arg);
@ -533,7 +533,7 @@ dummy_func(
} }
macro(BINARY_OP_INPLACE_ADD_UNICODE) = macro(BINARY_OP_INPLACE_ADD_UNICODE) =
_GUARD_BOTH_UNICODE + _BINARY_OP_INPLACE_ADD_UNICODE; _GUARD_BOTH_UNICODE + unused/1 + _BINARY_OP_INPLACE_ADD_UNICODE;
family(BINARY_SUBSCR, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = { family(BINARY_SUBSCR, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = {
BINARY_SUBSCR_DICT, BINARY_SUBSCR_DICT,
@ -1295,14 +1295,14 @@ dummy_func(
#endif /* ENABLE_SPECIALIZATION */ #endif /* ENABLE_SPECIALIZATION */
} }
op(_STORE_ATTR, (unused/3, v, owner --)) { op(_STORE_ATTR, (v, owner --)) {
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
int err = PyObject_SetAttr(owner, name, v); int err = PyObject_SetAttr(owner, name, v);
DECREF_INPUTS(); DECREF_INPUTS();
ERROR_IF(err, error); ERROR_IF(err, error);
} }
macro(STORE_ATTR) = _SPECIALIZE_STORE_ATTR + _STORE_ATTR; macro(STORE_ATTR) = _SPECIALIZE_STORE_ATTR + unused/3 + _STORE_ATTR;
inst(DELETE_ATTR, (owner --)) { inst(DELETE_ATTR, (owner --)) {
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
@ -1414,7 +1414,7 @@ dummy_func(
#endif /* ENABLE_SPECIALIZATION */ #endif /* ENABLE_SPECIALIZATION */
} }
op(_LOAD_GLOBAL, (unused/1, unused/1, unused/1 -- res, null if (oparg & 1))) { op(_LOAD_GLOBAL, ( -- res, null if (oparg & 1))) {
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1);
if (PyDict_CheckExact(GLOBALS()) if (PyDict_CheckExact(GLOBALS())
&& PyDict_CheckExact(BUILTINS())) && PyDict_CheckExact(BUILTINS()))
@ -1451,7 +1451,12 @@ dummy_func(
null = NULL; null = NULL;
} }
macro(LOAD_GLOBAL) = _SPECIALIZE_LOAD_GLOBAL + _LOAD_GLOBAL; macro(LOAD_GLOBAL) =
_SPECIALIZE_LOAD_GLOBAL +
counter/1 +
globals_version/1 +
builtins_version/1 +
_LOAD_GLOBAL;
op(_GUARD_GLOBALS_VERSION, (version/1 --)) { op(_GUARD_GLOBALS_VERSION, (version/1 --)) {
PyDictObject *dict = (PyDictObject *)GLOBALS(); PyDictObject *dict = (PyDictObject *)GLOBALS();
@ -1853,7 +1858,7 @@ dummy_func(
#endif /* ENABLE_SPECIALIZATION */ #endif /* ENABLE_SPECIALIZATION */
} }
op(_LOAD_ATTR, (unused/8, owner -- attr, self_or_null if (oparg & 1))) { op(_LOAD_ATTR, (owner -- attr, self_or_null if (oparg & 1))) {
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1);
if (oparg & 1) { if (oparg & 1) {
/* Designed to work in tandem with CALL, pushes two values. */ /* Designed to work in tandem with CALL, pushes two values. */
@ -1886,7 +1891,10 @@ dummy_func(
} }
} }
macro(LOAD_ATTR) = _SPECIALIZE_LOAD_ATTR + _LOAD_ATTR; macro(LOAD_ATTR) =
_SPECIALIZE_LOAD_ATTR +
unused/8 +
_LOAD_ATTR;
pseudo(LOAD_METHOD) = { pseudo(LOAD_METHOD) = {
LOAD_ATTR, LOAD_ATTR,
@ -2369,7 +2377,7 @@ dummy_func(
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
} }
replaced op(_POP_JUMP_IF_FALSE, (unused/1, cond -- )) { replaced op(_POP_JUMP_IF_FALSE, (cond -- )) {
assert(PyBool_Check(cond)); assert(PyBool_Check(cond));
int flag = Py_IsFalse(cond); int flag = Py_IsFalse(cond);
#if ENABLE_SPECIALIZATION #if ENABLE_SPECIALIZATION
@ -2378,7 +2386,7 @@ dummy_func(
JUMPBY(oparg * flag); JUMPBY(oparg * flag);
} }
replaced op(_POP_JUMP_IF_TRUE, (unused/1, cond -- )) { replaced op(_POP_JUMP_IF_TRUE, (cond -- )) {
assert(PyBool_Check(cond)); assert(PyBool_Check(cond));
int flag = Py_IsTrue(cond); int flag = Py_IsTrue(cond);
#if ENABLE_SPECIALIZATION #if ENABLE_SPECIALIZATION
@ -2397,13 +2405,13 @@ dummy_func(
} }
} }
macro(POP_JUMP_IF_TRUE) = _POP_JUMP_IF_TRUE; macro(POP_JUMP_IF_TRUE) = unused/1 + _POP_JUMP_IF_TRUE;
macro(POP_JUMP_IF_FALSE) = _POP_JUMP_IF_FALSE; macro(POP_JUMP_IF_FALSE) = unused/1 + _POP_JUMP_IF_FALSE;
macro(POP_JUMP_IF_NONE) = _IS_NONE + _POP_JUMP_IF_TRUE; macro(POP_JUMP_IF_NONE) = unused/1 + _IS_NONE + _POP_JUMP_IF_TRUE;
macro(POP_JUMP_IF_NOT_NONE) = _IS_NONE + _POP_JUMP_IF_FALSE; macro(POP_JUMP_IF_NOT_NONE) = unused/1 + _IS_NONE + _POP_JUMP_IF_FALSE;
inst(JUMP_BACKWARD_NO_INTERRUPT, (--)) { inst(JUMP_BACKWARD_NO_INTERRUPT, (--)) {
TIER_ONE_ONLY TIER_ONE_ONLY
@ -3010,7 +3018,7 @@ dummy_func(
} }
// When calling Python, inline the call using DISPATCH_INLINED(). // When calling Python, inline the call using DISPATCH_INLINED().
op(_CALL, (unused/2, callable, self_or_null, args[oparg] -- res)) { op(_CALL, (callable, self_or_null, args[oparg] -- res)) {
// oparg counts all of the args, but *not* self: // oparg counts all of the args, but *not* self:
int total_args = oparg; int total_args = oparg;
if (self_or_null != NULL) { if (self_or_null != NULL) {
@ -3079,7 +3087,7 @@ dummy_func(
CHECK_EVAL_BREAKER(); CHECK_EVAL_BREAKER();
} }
macro(CALL) = _SPECIALIZE_CALL + _CALL; macro(CALL) = _SPECIALIZE_CALL + unused/2 + _CALL;
op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- callable, null, unused[oparg])) { op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- callable, null, unused[oparg])) {
DEOPT_IF(null != NULL); DEOPT_IF(null != NULL);

View file

@ -24,6 +24,7 @@
#include "pycore_sysmodule.h" // _PySys_Audit() #include "pycore_sysmodule.h" // _PySys_Audit()
#include "pycore_tuple.h" // _PyTuple_ITEMS() #include "pycore_tuple.h" // _PyTuple_ITEMS()
#include "pycore_typeobject.h" // _PySuper_Lookup() #include "pycore_typeobject.h" // _PySuper_Lookup()
#include "pycore_uop_ids.h" // Uops
#include "pycore_uops.h" // _PyUOpExecutorObject #include "pycore_uops.h" // _PyUOpExecutorObject
#include "pycore_pyerrors.h" #include "pycore_pyerrors.h"

View file

@ -796,36 +796,13 @@ stack_effect(int opcode, int oparg, int jump)
// Specialized instructions are not supported. // Specialized instructions are not supported.
return PY_INVALID_STACK_EFFECT; return PY_INVALID_STACK_EFFECT;
} }
int popped, pushed; int popped = _PyOpcode_num_popped(opcode, oparg);
if (jump > 0) { int pushed = _PyOpcode_num_pushed(opcode, oparg);
popped = _PyOpcode_num_popped(opcode, oparg, true);
pushed = _PyOpcode_num_pushed(opcode, oparg, true);
}
else {
popped = _PyOpcode_num_popped(opcode, oparg, false);
pushed = _PyOpcode_num_pushed(opcode, oparg, false);
}
if (popped < 0 || pushed < 0) { if (popped < 0 || pushed < 0) {
return PY_INVALID_STACK_EFFECT; return PY_INVALID_STACK_EFFECT;
} }
if (jump >= 0) {
return pushed - popped; return pushed - popped;
} }
if (jump < 0) {
// Compute max(pushed - popped, alt_pushed - alt_popped)
int alt_popped = _PyOpcode_num_popped(opcode, oparg, true);
int alt_pushed = _PyOpcode_num_pushed(opcode, oparg, true);
if (alt_popped < 0 || alt_pushed < 0) {
return PY_INVALID_STACK_EFFECT;
}
int diff = pushed - popped;
int alt_diff = alt_pushed - alt_popped;
if (alt_diff > diff) {
return alt_diff;
}
return diff;
}
}
// Pseudo ops // Pseudo ops
switch (opcode) { switch (opcode) {
@ -1125,7 +1102,7 @@ compiler_addop_name(struct compiler_unit *u, location loc,
arg <<= 1; arg <<= 1;
} }
if (opcode == LOAD_METHOD) { if (opcode == LOAD_METHOD) {
assert(SAME_OPCODE_METADATA(LOAD_METHOD, LOAD_ATTR)); assert(is_pseudo_target(LOAD_METHOD, LOAD_ATTR));
opcode = LOAD_ATTR; opcode = LOAD_ATTR;
arg <<= 1; arg <<= 1;
arg |= 1; arg |= 1;
@ -1135,18 +1112,18 @@ compiler_addop_name(struct compiler_unit *u, location loc,
arg |= 2; arg |= 2;
} }
if (opcode == LOAD_SUPER_METHOD) { if (opcode == LOAD_SUPER_METHOD) {
assert(SAME_OPCODE_METADATA(LOAD_SUPER_METHOD, LOAD_SUPER_ATTR)); assert(is_pseudo_target(LOAD_SUPER_METHOD, LOAD_SUPER_ATTR));
opcode = LOAD_SUPER_ATTR; opcode = LOAD_SUPER_ATTR;
arg <<= 2; arg <<= 2;
arg |= 3; arg |= 3;
} }
if (opcode == LOAD_ZERO_SUPER_ATTR) { if (opcode == LOAD_ZERO_SUPER_ATTR) {
assert(SAME_OPCODE_METADATA(LOAD_ZERO_SUPER_ATTR, LOAD_SUPER_ATTR)); assert(is_pseudo_target(LOAD_ZERO_SUPER_ATTR, LOAD_SUPER_ATTR));
opcode = LOAD_SUPER_ATTR; opcode = LOAD_SUPER_ATTR;
arg <<= 2; arg <<= 2;
} }
if (opcode == LOAD_ZERO_SUPER_METHOD) { if (opcode == LOAD_ZERO_SUPER_METHOD) {
assert(SAME_OPCODE_METADATA(LOAD_ZERO_SUPER_METHOD, LOAD_SUPER_ATTR)); assert(is_pseudo_target(LOAD_ZERO_SUPER_METHOD, LOAD_SUPER_ATTR));
opcode = LOAD_SUPER_ATTR; opcode = LOAD_SUPER_ATTR;
arg <<= 2; arg <<= 2;
arg |= 1; arg |= 1;

View file

@ -2258,11 +2258,11 @@ convert_pseudo_ops(basicblock *entryblock)
INSTR_SET_OP0(instr, NOP); INSTR_SET_OP0(instr, NOP);
} }
else if (instr->i_opcode == LOAD_CLOSURE) { else if (instr->i_opcode == LOAD_CLOSURE) {
assert(SAME_OPCODE_METADATA(LOAD_CLOSURE, LOAD_FAST)); assert(is_pseudo_target(LOAD_CLOSURE, LOAD_FAST));
instr->i_opcode = LOAD_FAST; instr->i_opcode = LOAD_FAST;
} }
else if (instr->i_opcode == STORE_FAST_MAYBE_NULL) { else if (instr->i_opcode == STORE_FAST_MAYBE_NULL) {
assert(SAME_OPCODE_METADATA(STORE_FAST_MAYBE_NULL, STORE_FAST)); assert(is_pseudo_target(STORE_FAST_MAYBE_NULL, STORE_FAST));
instr->i_opcode = STORE_FAST; instr->i_opcode = STORE_FAST;
} }
} }

View file

@ -153,6 +153,7 @@
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP);
} }
/* Skip 1 cache entry */
// _BINARY_OP_ADD_FLOAT // _BINARY_OP_ADD_FLOAT
{ {
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
@ -181,6 +182,7 @@
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP);
} }
/* Skip 1 cache entry */
// _BINARY_OP_ADD_INT // _BINARY_OP_ADD_INT
{ {
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
@ -209,6 +211,7 @@
DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP);
} }
/* Skip 1 cache entry */
// _BINARY_OP_ADD_UNICODE // _BINARY_OP_ADD_UNICODE
{ {
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
@ -236,6 +239,7 @@
DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP);
} }
/* Skip 1 cache entry */
// _BINARY_OP_INPLACE_ADD_UNICODE // _BINARY_OP_INPLACE_ADD_UNICODE
{ {
TIER_ONE_ONLY TIER_ONE_ONLY
@ -282,6 +286,7 @@
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP);
} }
/* Skip 1 cache entry */
// _BINARY_OP_MULTIPLY_FLOAT // _BINARY_OP_MULTIPLY_FLOAT
{ {
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
@ -310,6 +315,7 @@
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP);
} }
/* Skip 1 cache entry */
// _BINARY_OP_MULTIPLY_INT // _BINARY_OP_MULTIPLY_INT
{ {
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
@ -338,6 +344,7 @@
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP);
} }
/* Skip 1 cache entry */
// _BINARY_OP_SUBTRACT_FLOAT // _BINARY_OP_SUBTRACT_FLOAT
{ {
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
@ -366,6 +373,7 @@
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP);
} }
/* Skip 1 cache entry */
// _BINARY_OP_SUBTRACT_INT // _BINARY_OP_SUBTRACT_INT
{ {
STAT_INC(BINARY_OP, hit); STAT_INC(BINARY_OP, hit);
@ -763,6 +771,7 @@
DECREMENT_ADAPTIVE_COUNTER(this_instr[1].cache); DECREMENT_ADAPTIVE_COUNTER(this_instr[1].cache);
#endif /* ENABLE_SPECIALIZATION */ #endif /* ENABLE_SPECIALIZATION */
} }
/* Skip 2 cache entries */
// _CALL // _CALL
{ {
// oparg counts all of the args, but *not* self: // oparg counts all of the args, but *not* self:
@ -3400,6 +3409,7 @@
DECREMENT_ADAPTIVE_COUNTER(this_instr[1].cache); DECREMENT_ADAPTIVE_COUNTER(this_instr[1].cache);
#endif /* ENABLE_SPECIALIZATION */ #endif /* ENABLE_SPECIALIZATION */
} }
/* Skip 8 cache entries */
// _LOAD_ATTR // _LOAD_ATTR
{ {
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1);
@ -4096,6 +4106,9 @@
DECREMENT_ADAPTIVE_COUNTER(this_instr[1].cache); DECREMENT_ADAPTIVE_COUNTER(this_instr[1].cache);
#endif /* ENABLE_SPECIALIZATION */ #endif /* ENABLE_SPECIALIZATION */
} }
/* Skip 1 cache entry */
/* Skip 1 cache entry */
/* Skip 1 cache entry */
// _LOAD_GLOBAL // _LOAD_GLOBAL
{ {
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1);
@ -4564,6 +4577,7 @@
next_instr += 2; next_instr += 2;
INSTRUCTION_STATS(POP_JUMP_IF_FALSE); INSTRUCTION_STATS(POP_JUMP_IF_FALSE);
PyObject *cond; PyObject *cond;
/* Skip 1 cache entry */
cond = stack_pointer[-1]; cond = stack_pointer[-1];
assert(PyBool_Check(cond)); assert(PyBool_Check(cond));
int flag = Py_IsFalse(cond); int flag = Py_IsFalse(cond);
@ -4582,6 +4596,7 @@
PyObject *value; PyObject *value;
PyObject *b; PyObject *b;
PyObject *cond; PyObject *cond;
/* Skip 1 cache entry */
// _IS_NONE // _IS_NONE
value = stack_pointer[-1]; value = stack_pointer[-1];
{ {
@ -4614,6 +4629,7 @@
PyObject *value; PyObject *value;
PyObject *b; PyObject *b;
PyObject *cond; PyObject *cond;
/* Skip 1 cache entry */
// _IS_NONE // _IS_NONE
value = stack_pointer[-1]; value = stack_pointer[-1];
{ {
@ -4644,6 +4660,7 @@
next_instr += 2; next_instr += 2;
INSTRUCTION_STATS(POP_JUMP_IF_TRUE); INSTRUCTION_STATS(POP_JUMP_IF_TRUE);
PyObject *cond; PyObject *cond;
/* Skip 1 cache entry */
cond = stack_pointer[-1]; cond = stack_pointer[-1];
assert(PyBool_Check(cond)); assert(PyBool_Check(cond));
int flag = Py_IsTrue(cond); int flag = Py_IsTrue(cond);
@ -5117,6 +5134,7 @@
DECREMENT_ADAPTIVE_COUNTER(this_instr[1].cache); DECREMENT_ADAPTIVE_COUNTER(this_instr[1].cache);
#endif /* ENABLE_SPECIALIZATION */ #endif /* ENABLE_SPECIALIZATION */
} }
/* Skip 3 cache entries */
// _STORE_ATTR // _STORE_ATTR
v = stack_pointer[-2]; v = stack_pointer[-2];
{ {
@ -5509,6 +5527,7 @@
DECREMENT_ADAPTIVE_COUNTER(this_instr[1].cache); DECREMENT_ADAPTIVE_COUNTER(this_instr[1].cache);
#endif /* ENABLE_SPECIALIZATION */ #endif /* ENABLE_SPECIALIZATION */
} }
/* Skip 2 cache entries */
// _TO_BOOL // _TO_BOOL
{ {
int err = PyObject_IsTrue(value); int err = PyObject_IsTrue(value);

View file

@ -6,14 +6,20 @@
#include "pycore_opcode_utils.h" // MAX_REAL_OPCODE #include "pycore_opcode_utils.h" // MAX_REAL_OPCODE
#include "pycore_optimizer.h" // _Py_uop_analyze_and_optimize() #include "pycore_optimizer.h" // _Py_uop_analyze_and_optimize()
#include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_uop_ids.h"
#include "pycore_uops.h" #include "pycore_uops.h"
#include "cpython/optimizer.h" #include "cpython/optimizer.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#define NEED_OPCODE_METADATA
#include "pycore_uop_metadata.h" // Uop tables
#undef NEED_OPCODE_METADATA
#define MAX_EXECUTORS_SIZE 256 #define MAX_EXECUTORS_SIZE 256
static bool static bool
has_space_for_executor(PyCodeObject *code, _Py_CODEUNIT *instr) has_space_for_executor(PyCodeObject *code, _Py_CODEUNIT *instr)
{ {
@ -327,9 +333,6 @@ uop_dealloc(_PyUOpExecutorObject *self) {
const char * const char *
_PyUOpName(int index) _PyUOpName(int index)
{ {
if (index <= MAX_REAL_OPCODE) {
return _PyOpcode_OpName[index];
}
return _PyOpcode_uop_name[index]; return _PyOpcode_uop_name[index];
} }
@ -388,7 +391,7 @@ PyTypeObject _PyUOpExecutor_Type = {
/* TO DO -- Generate these tables */ /* TO DO -- Generate these tables */
static const uint16_t static const uint16_t
_PyUOp_Replacements[OPCODE_METADATA_SIZE] = { _PyUOp_Replacements[MAX_UOP_ID + 1] = {
[_ITER_JUMP_RANGE] = _GUARD_NOT_EXHAUSTED_RANGE, [_ITER_JUMP_RANGE] = _GUARD_NOT_EXHAUSTED_RANGE,
[_ITER_JUMP_LIST] = _GUARD_NOT_EXHAUSTED_LIST, [_ITER_JUMP_LIST] = _GUARD_NOT_EXHAUSTED_LIST,
[_ITER_JUMP_TUPLE] = _GUARD_NOT_EXHAUSTED_TUPLE, [_ITER_JUMP_TUPLE] = _GUARD_NOT_EXHAUSTED_TUPLE,
@ -629,14 +632,6 @@ top: // Jump here after _PUSH_FRAME or likely branches
oparg += extras; oparg += extras;
} }
} }
if (_PyUOp_Replacements[uop]) {
uop = _PyUOp_Replacements[uop];
if (uop == _FOR_ITER_TIER_TWO) {
target += 1 + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1;
assert(_PyCode_CODE(code)[target-1].op.code == END_FOR ||
_PyCode_CODE(code)[target-1].op.code == INSTRUMENTED_END_FOR);
}
}
break; break;
case OPARG_CACHE_1: case OPARG_CACHE_1:
operand = read_u16(&instr[offset].cache); operand = read_u16(&instr[offset].cache);
@ -657,7 +652,15 @@ top: // Jump here after _PUSH_FRAME or likely branches
oparg = offset; oparg = offset;
assert(uop == _SAVE_RETURN_OFFSET); assert(uop == _SAVE_RETURN_OFFSET);
break; break;
case OPARG_REPLACED:
uop = _PyUOp_Replacements[uop];
assert(uop != 0);
if (uop == _FOR_ITER_TIER_TWO) {
target += 1 + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1;
assert(_PyCode_CODE(code)[target-1].op.code == END_FOR ||
_PyCode_CODE(code)[target-1].op.code == INSTRUMENTED_END_FOR);
}
break;
default: default:
fprintf(stderr, fprintf(stderr,
"opcode=%d, oparg=%d; nuops=%d, i=%d; size=%d, offset=%d\n", "opcode=%d, oparg=%d; nuops=%d, i=%d; size=%d, offset=%d\n",
@ -799,7 +802,8 @@ compute_used(_PyUOpInstruction *buffer, uint32_t *used)
} }
/* All other micro-ops fall through, so i+1 is reachable */ /* All other micro-ops fall through, so i+1 is reachable */
SET_BIT(used, i+1); SET_BIT(used, i+1);
if (OPCODE_HAS_JUMP(opcode)) { assert(opcode <= MAX_UOP_ID);
if (_PyUop_Flags[opcode] & HAS_JUMP_FLAG) {
/* Mark target as reachable */ /* Mark target as reachable */
SET_BIT(used, buffer[i].oparg); SET_BIT(used, buffer[i].oparg);
} }

View file

@ -10,6 +10,7 @@
#include "pycore_moduleobject.h" #include "pycore_moduleobject.h"
#include "pycore_object.h" #include "pycore_object.h"
#include "pycore_opcode_metadata.h" // _PyOpcode_Caches #include "pycore_opcode_metadata.h" // _PyOpcode_Caches
#include "pycore_uop_metadata.h" // _PyOpcode_uop_name
#include "pycore_opcode_utils.h" // RESUME_AT_FUNC_START #include "pycore_opcode_utils.h" // RESUME_AT_FUNC_START
#include "pycore_pylifecycle.h" // _PyOS_URandomNonblock() #include "pycore_pylifecycle.h" // _PyOS_URandomNonblock()
#include "pycore_runtime.h" // _Py_ID() #include "pycore_runtime.h" // _Py_ID()

View file

@ -11,11 +11,16 @@ class Properties:
deopts: bool deopts: bool
oparg: bool oparg: bool
jumps: bool jumps: bool
eval_breaker: bool
ends_with_eval_breaker: bool ends_with_eval_breaker: bool
needs_this: bool needs_this: bool
always_exits: bool always_exits: bool
stores_sp: bool stores_sp: bool
tier_one_only: bool tier_one_only: bool
uses_co_consts: bool
uses_co_names: bool
uses_locals: bool
has_free: bool
def dump(self, indent: str) -> None: def dump(self, indent: str) -> None:
print(indent, end="") print(indent, end="")
@ -30,11 +35,16 @@ class Properties:
deopts=any(p.deopts for p in properties), deopts=any(p.deopts for p in properties),
oparg=any(p.oparg for p in properties), oparg=any(p.oparg for p in properties),
jumps=any(p.jumps for p in properties), jumps=any(p.jumps for p in properties),
eval_breaker=any(p.eval_breaker for p in properties),
ends_with_eval_breaker=any(p.ends_with_eval_breaker for p in properties), ends_with_eval_breaker=any(p.ends_with_eval_breaker for p in properties),
needs_this=any(p.needs_this for p in properties), needs_this=any(p.needs_this for p in properties),
always_exits=any(p.always_exits for p in properties), always_exits=any(p.always_exits for p in properties),
stores_sp=any(p.stores_sp for p in properties), stores_sp=any(p.stores_sp for p in properties),
tier_one_only=any(p.tier_one_only for p in properties), tier_one_only=any(p.tier_one_only for p in properties),
uses_co_consts=any(p.uses_co_consts for p in properties),
uses_co_names=any(p.uses_co_names for p in properties),
uses_locals=any(p.uses_locals for p in properties),
has_free=any(p.has_free for p in properties),
) )
@ -44,11 +54,16 @@ SKIP_PROPERTIES = Properties(
deopts=False, deopts=False,
oparg=False, oparg=False,
jumps=False, jumps=False,
eval_breaker=False,
ends_with_eval_breaker=False, ends_with_eval_breaker=False,
needs_this=False, needs_this=False,
always_exits=False, always_exits=False,
stores_sp=False, stores_sp=False,
tier_one_only=False, tier_one_only=False,
uses_co_consts=False,
uses_co_names=False,
uses_locals=False,
has_free=False,
) )
@ -142,6 +157,12 @@ class Uop:
return False return False
return True return True
def is_super(self) -> bool:
for tkn in self.body:
if tkn.kind == "IDENTIFIER" and tkn.text == "oparg1":
return True
return False
Part = Uop | Skip Part = Uop | Skip
@ -153,6 +174,7 @@ class Instruction:
_properties: Properties | None _properties: Properties | None
is_target: bool = False is_target: bool = False
family: Optional["Family"] = None family: Optional["Family"] = None
opcode: int = -1
@property @property
def properties(self) -> Properties: def properties(self) -> Properties:
@ -171,16 +193,30 @@ class Instruction:
def size(self) -> int: def size(self) -> int:
return 1 + sum(part.size for part in self.parts) return 1 + sum(part.size for part in self.parts)
def is_super(self) -> bool:
if len(self.parts) != 1:
return False
uop = self.parts[0]
if isinstance(uop, Uop):
return uop.is_super()
else:
return False
@dataclass @dataclass
class PseudoInstruction: class PseudoInstruction:
name: str name: str
targets: list[Instruction] targets: list[Instruction]
flags: list[str] flags: list[str]
opcode: int = -1
def dump(self, indent: str) -> None: def dump(self, indent: str) -> None:
print(indent, self.name, "->", " or ".join([t.name for t in self.targets])) print(indent, self.name, "->", " or ".join([t.name for t in self.targets]))
@property
def properties(self) -> Properties:
return Properties.from_list([i.properties for i in self.targets])
@dataclass @dataclass
class Family: class Family:
@ -198,12 +234,15 @@ class Analysis:
uops: dict[str, Uop] uops: dict[str, Uop]
families: dict[str, Family] families: dict[str, Family]
pseudos: dict[str, PseudoInstruction] pseudos: dict[str, PseudoInstruction]
opmap: dict[str, int]
have_arg: int
min_instrumented: int
def analysis_error(message: str, tkn: lexer.Token) -> SyntaxError: def analysis_error(message: str, tkn: lexer.Token) -> SyntaxError:
# To do -- support file and line output # To do -- support file and line output
# Construct a SyntaxError instance from message and token # Construct a SyntaxError instance from message and token
return lexer.make_syntax_error(message, "", tkn.line, tkn.column, "") return lexer.make_syntax_error(message, tkn.filename, tkn.line, tkn.column, "")
def override_error( def override_error(
@ -238,6 +277,11 @@ def analyze_caches(inputs: list[parser.InputEffect]) -> list[CacheEntry]:
caches: list[parser.CacheEffect] = [ caches: list[parser.CacheEffect] = [
i for i in inputs if isinstance(i, parser.CacheEffect) i for i in inputs if isinstance(i, parser.CacheEffect)
] ]
for cache in caches:
if cache.name == "unused":
raise analysis_error(
"Unused cache entry in op. Move to enclosing macro.", cache.tokens[0]
)
return [CacheEntry(i.name, int(i.size)) for i in caches] return [CacheEntry(i.name, int(i.size)) for i in caches]
@ -300,17 +344,28 @@ def always_exits(op: parser.InstDef) -> bool:
def compute_properties(op: parser.InstDef) -> Properties: def compute_properties(op: parser.InstDef) -> Properties:
has_free = (
variable_used(op, "PyCell_New")
or variable_used(op, "PyCell_GET")
or variable_used(op, "PyCell_SET")
)
return Properties( return Properties(
escapes=makes_escaping_api_call(op), escapes=makes_escaping_api_call(op),
infallible=is_infallible(op), infallible=is_infallible(op),
deopts=variable_used(op, "DEOPT_IF"), deopts=variable_used(op, "DEOPT_IF"),
oparg=variable_used(op, "oparg"), oparg=variable_used(op, "oparg"),
jumps=variable_used(op, "JUMPBY"), jumps=variable_used(op, "JUMPBY"),
eval_breaker=variable_used(op, "CHECK_EVAL_BREAKER"),
ends_with_eval_breaker=eval_breaker_at_end(op), ends_with_eval_breaker=eval_breaker_at_end(op),
needs_this=variable_used(op, "this_instr"), needs_this=variable_used(op, "this_instr"),
always_exits=always_exits(op), always_exits=always_exits(op),
stores_sp=variable_used(op, "STORE_SP"), stores_sp=variable_used(op, "STORE_SP"),
tier_one_only=variable_used(op, "TIER_ONE_ONLY"), tier_one_only=variable_used(op, "TIER_ONE_ONLY"),
uses_co_consts=variable_used(op, "FRAME_CO_CONSTS"),
uses_co_names=variable_used(op, "FRAME_CO_NAMES"),
uses_locals=(variable_used(op, "GETLOCAL") or variable_used(op, "SETLOCAL"))
and not has_free,
has_free=has_free,
) )
@ -417,6 +472,95 @@ def add_pseudo(
) )
def assign_opcodes(
instructions: dict[str, Instruction],
families: dict[str, Family],
pseudos: dict[str, PseudoInstruction],
) -> tuple[dict[str, int], int, int]:
"""Assigns opcodes, then returns the opmap,
have_arg and min_instrumented values"""
instmap: dict[str, int] = {}
# 0 is reserved for cache entries. This helps debugging.
instmap["CACHE"] = 0
# 17 is reserved as it is the initial value for the specializing counter.
# This helps catch cases where we attempt to execute a cache.
instmap["RESERVED"] = 17
# 149 is RESUME - it is hard coded as such in Tools/build/deepfreeze.py
instmap["RESUME"] = 149
# This is an historical oddity.
instmap["BINARY_OP_INPLACE_ADD_UNICODE"] = 3
instmap["INSTRUMENTED_LINE"] = 254
instrumented = [name for name in instructions if name.startswith("INSTRUMENTED")]
# Special case: this instruction is implemented in ceval.c
# rather than bytecodes.c, so we need to add it explicitly
# here (at least until we add something to bytecodes.c to
# declare external instructions).
instrumented.append("INSTRUMENTED_LINE")
specialized: set[str] = set()
no_arg: list[str] = []
has_arg: list[str] = []
for family in families.values():
specialized.update(inst.name for inst in family.members)
for inst in instructions.values():
name = inst.name
if name in specialized:
continue
if name in instrumented:
continue
if inst.properties.oparg:
has_arg.append(name)
else:
no_arg.append(name)
# Specialized ops appear in their own section
# Instrumented opcodes are at the end of the valid range
min_internal = 150
min_instrumented = 254 - (len(instrumented) - 1)
assert min_internal + len(specialized) < min_instrumented
next_opcode = 1
def add_instruction(name: str) -> None:
nonlocal next_opcode
if name in instmap:
return # Pre-defined name
while next_opcode in instmap.values():
next_opcode += 1
instmap[name] = next_opcode
next_opcode += 1
for name in sorted(no_arg):
add_instruction(name)
for name in sorted(has_arg):
add_instruction(name)
# For compatibility
next_opcode = min_internal
for name in sorted(specialized):
add_instruction(name)
next_opcode = min_instrumented
for name in instrumented:
add_instruction(name)
for name in instructions:
instructions[name].opcode = instmap[name]
for op, name in enumerate(sorted(pseudos), 256):
instmap[name] = op
pseudos[name].opcode = op
return instmap, len(no_arg), min_instrumented
def analyze_forest(forest: list[parser.AstNode]) -> Analysis: def analyze_forest(forest: list[parser.AstNode]) -> Analysis:
instructions: dict[str, Instruction] = {} instructions: dict[str, Instruction] = {}
uops: dict[str, Uop] = {} uops: dict[str, Uop] = {}
@ -460,10 +604,20 @@ def analyze_forest(forest: list[parser.AstNode]) -> Analysis:
continue continue
if target.text in instructions: if target.text in instructions:
instructions[target.text].is_target = True instructions[target.text].is_target = True
# Hack # Special case BINARY_OP_INPLACE_ADD_UNICODE
# BINARY_OP_INPLACE_ADD_UNICODE is not a normal family member,
# as it is the wrong size, but we need it to maintain an
# historical optimization.
if "BINARY_OP_INPLACE_ADD_UNICODE" in instructions: if "BINARY_OP_INPLACE_ADD_UNICODE" in instructions:
instructions["BINARY_OP_INPLACE_ADD_UNICODE"].family = families["BINARY_OP"] inst = instructions["BINARY_OP_INPLACE_ADD_UNICODE"]
return Analysis(instructions, uops, families, pseudos) inst.family = families["BINARY_OP"]
families["BINARY_OP"].members.append(inst)
opmap, first_arg, min_instrumented = assign_opcodes(
instructions, families, pseudos
)
return Analysis(
instructions, uops, families, pseudos, opmap, first_arg, min_instrumented
)
def analyze_files(filenames: list[str]) -> Analysis: def analyze_files(filenames: list[str]) -> Analysis:

View file

@ -1,5 +1,6 @@
import contextlib
from lexer import Token from lexer import Token
from typing import TextIO from typing import TextIO, Iterator
class CWriter: class CWriter:
@ -44,16 +45,20 @@ class CWriter:
def maybe_indent(self, txt: str) -> None: def maybe_indent(self, txt: str) -> None:
parens = txt.count("(") - txt.count(")") parens = txt.count("(") - txt.count(")")
if parens > 0 and self.last_token: if parens > 0:
if self.last_token:
offset = self.last_token.end_column - 1 offset = self.last_token.end_column - 1
if offset <= self.indents[-1] or offset > 40: if offset <= self.indents[-1] or offset > 40:
offset = self.indents[-1] + 4 offset = self.indents[-1] + 4
else:
offset = self.indents[-1] + 4
self.indents.append(offset) self.indents.append(offset)
if is_label(txt): if is_label(txt):
self.indents.append(self.indents[-1] + 4) self.indents.append(self.indents[-1] + 4)
else: else:
braces = txt.count("{") - txt.count("}") braces = txt.count("{") - txt.count("}")
if braces > 0: if braces > 0:
assert braces == 1
if 'extern "C"' in txt: if 'extern "C"' in txt:
self.indents.append(self.indents[-1]) self.indents.append(self.indents[-1])
else: else:
@ -114,6 +119,28 @@ class CWriter:
self.newline = True self.newline = True
self.last_token = None self.last_token = None
@contextlib.contextmanager
def header_guard(self, name: str) -> Iterator[None]:
self.out.write(
f"""
#ifndef {name}
#define {name}
#ifdef __cplusplus
extern "C" {{
#endif
"""
)
yield
self.out.write(
f"""
#ifdef __cplusplus
}}
#endif
#endif /* !{name} */
"""
)
def is_label(txt: str) -> bool: def is_label(txt: str) -> bool:
return not txt.startswith("//") and txt.endswith(":") return not txt.startswith("//") and txt.endswith(":")

View file

@ -840,7 +840,6 @@ def main() -> None:
a.assign_opcode_ids() a.assign_opcode_ids()
a.write_opcode_targets(args.opcode_targets_h) a.write_opcode_targets(args.opcode_targets_h)
a.write_metadata(args.metadata, args.pymetadata)
a.write_abstract_interpreter_instructions( a.write_abstract_interpreter_instructions(
args.abstract_interpreter_cases, args.emit_line_directives args.abstract_interpreter_cases, args.emit_line_directives
) )

View file

@ -2,14 +2,11 @@ from pathlib import Path
from typing import TextIO from typing import TextIO
from analyzer import ( from analyzer import (
Analysis,
Instruction, Instruction,
Uop, Uop,
Part,
analyze_files, analyze_files,
Properties,
Skip, Skip,
StackItem,
analysis_error,
) )
from cwriter import CWriter from cwriter import CWriter
from typing import Callable, Mapping, TextIO, Iterator from typing import Callable, Mapping, TextIO, Iterator
@ -25,14 +22,16 @@ def root_relative_path(filename: str) -> str:
try: try:
return Path(filename).absolute().relative_to(ROOT).as_posix() return Path(filename).absolute().relative_to(ROOT).as_posix()
except ValueError: except ValueError:
# Not relative to root, just return original path.
return filename return filename
def write_header(generator: str, sources: list[str], outfile: TextIO) -> None:
def write_header(generator: str, sources: list[str], outfile: TextIO, comment: str = "//") -> None:
outfile.write( outfile.write(
f"""// This file is generated by {root_relative_path(generator)} f"""{comment} This file is generated by {root_relative_path(generator)}
// from: {comment} from:
// {", ".join(root_relative_path(src) for src in sources)} {comment} {", ".join(root_relative_path(src) for src in sources)}
// Do not edit! {comment} Do not edit!
""" """
) )
@ -186,3 +185,31 @@ def emit_tokens(
replacement_functions[tkn.text](out, tkn, tkn_iter, uop, stack, inst) replacement_functions[tkn.text](out, tkn, tkn_iter, uop, stack, inst)
else: else:
out.emit(tkn) out.emit(tkn)
def cflags(p: Properties) -> str:
flags: list[str] = []
if p.oparg:
flags.append("HAS_ARG_FLAG")
if p.uses_co_consts:
flags.append("HAS_CONST_FLAG")
if p.uses_co_names:
flags.append("HAS_NAME_FLAG")
if p.jumps:
flags.append("HAS_JUMP_FLAG")
if p.has_free:
flags.append("HAS_FREE_FLAG")
if p.uses_locals:
flags.append("HAS_LOCAL_FLAG")
if p.eval_breaker:
flags.append("HAS_EVAL_BREAK_FLAG")
if p.deopts:
flags.append("HAS_DEOPT_FLAG")
if not p.infallible:
flags.append("HAS_ERROR_FLAG")
if p.escapes:
flags.append("HAS_ESCAPES_FLAG")
if flags:
return " | ".join(flags)
else:
return "0"

View file

@ -24,111 +24,23 @@ from typing import TextIO
DEFAULT_OUTPUT = ROOT / "Include/opcode_ids.h" DEFAULT_OUTPUT = ROOT / "Include/opcode_ids.h"
def generate_opcode_header(filenames: list[str], analysis: Analysis, outfile: TextIO) -> None: def generate_opcode_header(
filenames: list[str], analysis: Analysis, outfile: TextIO
) -> None:
write_header(__file__, filenames, outfile) write_header(__file__, filenames, outfile)
out = CWriter(outfile, 0, False) out = CWriter(outfile, 0, False)
out.emit("\n") with out.header_guard("Py_OPCODE_IDS_H"):
instmap: dict[str, int] = {} out.emit("/* Instruction opcodes for compiled code */\n")
# 0 is reserved for cache entries. This helps debugging.
instmap["CACHE"] = 0
# 17 is reserved as it is the initial value for the specializing counter.
# This helps catch cases where we attempt to execute a cache.
instmap["RESERVED"] = 17
# 149 is RESUME - it is hard coded as such in Tools/build/deepfreeze.py
instmap["RESUME"] = 149
instmap["INSTRUMENTED_LINE"] = 254
instrumented = [
name for name in analysis.instructions if name.startswith("INSTRUMENTED")
]
# Special case: this instruction is implemented in ceval.c
# rather than bytecodes.c, so we need to add it explicitly
# here (at least until we add something to bytecodes.c to
# declare external instructions).
instrumented.append("INSTRUMENTED_LINE")
specialized: set[str] = set()
no_arg: list[str] = []
has_arg: list[str] = []
for family in analysis.families.values():
specialized.update(inst.name for inst in family.members)
for inst in analysis.instructions.values():
name = inst.name
if name in specialized:
continue
if name in instrumented:
continue
if inst.properties.oparg:
has_arg.append(name)
else:
no_arg.append(name)
# Specialized ops appear in their own section
# Instrumented opcodes are at the end of the valid range
min_internal = 150
min_instrumented = 254 - (len(instrumented) - 1)
assert min_internal + len(specialized) < min_instrumented
next_opcode = 1
def add_instruction(name: str) -> None:
nonlocal next_opcode
if name in instmap:
return # Pre-defined name
while next_opcode in instmap.values():
next_opcode += 1
instmap[name] = next_opcode
next_opcode += 1
for name in sorted(no_arg):
add_instruction(name)
for name in sorted(has_arg):
add_instruction(name)
# For compatibility
next_opcode = min_internal
for name in sorted(specialized):
add_instruction(name)
next_opcode = min_instrumented
for name in instrumented:
add_instruction(name)
for op, name in enumerate(sorted(analysis.pseudos), 256):
instmap[name] = op
assert 255 not in instmap.values()
out.emit(
"""#ifndef Py_OPCODE_IDS_H
#define Py_OPCODE_IDS_H
#ifdef __cplusplus
extern "C" {
#endif
/* Instruction opcodes for compiled code */
"""
)
def write_define(name: str, op: int) -> None: def write_define(name: str, op: int) -> None:
out.emit(f"#define {name:<38} {op:>3}\n") out.emit(f"#define {name:<38} {op:>3}\n")
for op, name in sorted([(op, name) for (name, op) in instmap.items()]): for op, name in sorted([(op, name) for (name, op) in analysis.opmap.items()]):
write_define(name, op) write_define(name, op)
out.emit("\n") out.emit("\n")
write_define("HAVE_ARGUMENT", len(no_arg)) write_define("HAVE_ARGUMENT", analysis.have_arg)
write_define("MIN_INSTRUMENTED_OPCODE", min_instrumented) write_define("MIN_INSTRUMENTED_OPCODE", analysis.min_instrumented)
out.emit("\n")
out.emit("#ifdef __cplusplus\n")
out.emit("}\n")
out.emit("#endif\n")
out.emit("#endif /* !Py_OPCODE_IDS_H */\n")
arg_parser = argparse.ArgumentParser( arg_parser = argparse.ArgumentParser(

View file

@ -0,0 +1,386 @@
"""Generate uop metedata.
Reads the instruction definitions from bytecodes.c.
Writes the metadata to pycore_uop_metadata.h by default.
"""
import argparse
import os.path
import sys
from analyzer import (
Analysis,
Instruction,
analyze_files,
Skip,
Uop,
)
from generators_common import (
DEFAULT_INPUT,
ROOT,
write_header,
cflags,
StackOffset,
)
from cwriter import CWriter
from typing import TextIO
from stack import get_stack_effect
# Constants used instead of size for macro expansions.
# Note: 1, 2, 4 must match actual cache entry sizes.
OPARG_KINDS = {
"OPARG_FULL": 0,
"OPARG_CACHE_1": 1,
"OPARG_CACHE_2": 2,
"OPARG_CACHE_4": 4,
"OPARG_TOP": 5,
"OPARG_BOTTOM": 6,
"OPARG_SAVE_RETURN_OFFSET": 7,
# Skip 8 as the other powers of 2 are sizes
"OPARG_REPLACED": 9,
}
FLAGS = [
"ARG",
"CONST",
"NAME",
"JUMP",
"FREE",
"LOCAL",
"EVAL_BREAK",
"DEOPT",
"ERROR",
"ESCAPES",
]
def generate_flag_macros(out: CWriter) -> None:
for i, flag in enumerate(FLAGS):
out.emit(f"#define HAS_{flag}_FLAG ({1<<i})\n")
for i, flag in enumerate(FLAGS):
out.emit(
f"#define OPCODE_HAS_{flag}(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_{flag}_FLAG))\n"
)
out.emit("\n")
def generate_oparg_macros(out: CWriter) -> None:
for name, value in OPARG_KINDS.items():
out.emit(f"#define {name} {value}\n")
out.emit("\n")
def emit_stack_effect_function(
out: CWriter, direction: str, data: list[tuple[str, str]]
) -> None:
out.emit(f"extern int _PyOpcode_num_{direction}(int opcode, int oparg);\n")
out.emit("#ifdef NEED_OPCODE_METADATA\n")
out.emit(f"int _PyOpcode_num_{direction}(int opcode, int oparg) {{\n")
out.emit("switch(opcode) {\n")
for name, effect in data:
out.emit(f"case {name}:\n")
out.emit(f" return {effect};\n")
out.emit("default:\n")
out.emit(" return -1;\n")
out.emit("}\n")
out.emit("}\n\n")
out.emit("#endif\n\n")
def generate_stack_effect_functions(analysis: Analysis, out: CWriter) -> None:
popped_data: list[tuple[str, str]] = []
pushed_data: list[tuple[str, str]] = []
for inst in analysis.instructions.values():
stack = get_stack_effect(inst)
popped = (-stack.base_offset).to_c()
pushed = (stack.top_offset - stack.base_offset).to_c()
popped_data.append((inst.name, popped))
pushed_data.append((inst.name, pushed))
emit_stack_effect_function(out, "popped", sorted(popped_data))
emit_stack_effect_function(out, "pushed", sorted(pushed_data))
def generate_is_pseudo(analysis: Analysis, out: CWriter) -> None:
"""Write the IS_PSEUDO_INSTR macro"""
out.emit("\n\n#define IS_PSEUDO_INSTR(OP) ( \\\n")
for op in analysis.pseudos:
out.emit(f"((OP) == {op}) || \\\n")
out.emit("0")
out.emit(")\n\n")
def get_format(inst: Instruction) -> str:
if inst.properties.oparg:
format = "INSTR_FMT_IB"
else:
format = "INSTR_FMT_IX"
if inst.size > 1:
format += "C"
format += "0" * (inst.size - 2)
return format
def generate_instruction_formats(analysis: Analysis, out: CWriter) -> None:
# Compute the set of all instruction formats.
formats: set[str] = set()
for inst in analysis.instructions.values():
formats.add(get_format(inst))
# Generate an enum for it
out.emit("enum InstructionFormat {\n")
next_id = 1
for format in sorted(formats):
out.emit(f"{format} = {next_id},\n")
next_id += 1
out.emit("};\n\n")
def generate_deopt_table(analysis: Analysis, out: CWriter) -> None:
out.emit("extern const uint8_t _PyOpcode_Deopt[256];\n")
out.emit("#ifdef NEED_OPCODE_METADATA\n")
out.emit("const uint8_t _PyOpcode_Deopt[256] = {\n")
deopts: list[tuple[str, str]] = []
for inst in analysis.instructions.values():
deopt = inst.name
if inst.family is not None:
deopt = inst.family.name
deopts.append((inst.name, deopt))
deopts.append(("INSTRUMENTED_LINE", "INSTRUMENTED_LINE"))
for name, deopt in sorted(deopts):
out.emit(f"[{name}] = {deopt},\n")
out.emit("};\n\n")
out.emit("#endif // NEED_OPCODE_METADATA\n\n")
def generate_cache_table(analysis: Analysis, out: CWriter) -> None:
out.emit("extern const uint8_t _PyOpcode_Caches[256];\n")
out.emit("#ifdef NEED_OPCODE_METADATA\n")
out.emit("const uint8_t _PyOpcode_Caches[256] = {\n")
for inst in analysis.instructions.values():
if inst.family and inst.family.name != inst.name:
continue
if inst.name.startswith("INSTRUMENTED"):
continue
if inst.size > 1:
out.emit(f"[{inst.name}] = {inst.size-1},\n")
out.emit("};\n")
out.emit("#endif\n\n")
def generate_name_table(analysis: Analysis, out: CWriter) -> None:
table_size = 256 + len(analysis.pseudos)
out.emit(f"extern const char *_PyOpcode_OpName[{table_size}];\n")
out.emit("#ifdef NEED_OPCODE_METADATA\n")
out.emit(f"const char *_PyOpcode_OpName[{table_size}] = {{\n")
names = list(analysis.instructions) + list(analysis.pseudos)
names.append("INSTRUMENTED_LINE")
for name in sorted(names):
out.emit(f'[{name}] = "{name}",\n')
out.emit("};\n")
out.emit("#endif\n\n")
def generate_metadata_table(analysis: Analysis, out: CWriter) -> None:
table_size = 256 + len(analysis.pseudos)
out.emit("struct opcode_metadata {\n")
out.emit("uint8_t valid_entry;\n")
out.emit("int8_t instr_format;\n")
out.emit("int16_t flags;\n")
out.emit("};\n\n")
out.emit(
f"extern const struct opcode_metadata _PyOpcode_opcode_metadata[{table_size}];\n"
)
out.emit("#ifdef NEED_OPCODE_METADATA\n")
out.emit(
f"const struct opcode_metadata _PyOpcode_opcode_metadata[{table_size}] = {{\n"
)
for inst in sorted(analysis.instructions.values(), key=lambda t: t.name):
out.emit(
f"[{inst.name}] = {{ true, {get_format(inst)}, {cflags(inst.properties)} }},\n"
)
for pseudo in sorted(analysis.pseudos.values(), key=lambda t: t.name):
flags = cflags(pseudo.properties)
for flag in pseudo.flags:
if flags == "0":
flags = f"{flag}_FLAG"
else:
flags += f" | {flag}_FLAG"
out.emit(f"[{pseudo.name}] = {{ true, -1, {flags} }},\n")
out.emit("};\n")
out.emit("#endif\n\n")
def generate_expansion_table(analysis: Analysis, out: CWriter) -> None:
expansions_table: dict[str, list[tuple[str, int, int]]] = {}
for inst in sorted(analysis.instructions.values(), key=lambda t: t.name):
offset: int = 0 # Cache effect offset
expansions: list[tuple[str, int, int]] = [] # [(name, size, offset), ...]
if inst.is_super():
pieces = inst.name.split("_")
assert len(pieces) == 4, f"{inst.name} doesn't look like a super-instr"
name1 = "_".join(pieces[:2])
name2 = "_".join(pieces[2:])
assert name1 in analysis.instructions, f"{name1} doesn't match any instr"
assert name2 in analysis.instructions, f"{name2} doesn't match any instr"
instr1 = analysis.instructions[name1]
instr2 = analysis.instructions[name2]
assert (
len(instr1.parts) == 1
), f"{name1} is not a good superinstruction part"
assert (
len(instr2.parts) == 1
), f"{name2} is not a good superinstruction part"
expansions.append((instr1.parts[0].name, OPARG_KINDS["OPARG_TOP"], 0))
expansions.append((instr2.parts[0].name, OPARG_KINDS["OPARG_BOTTOM"], 0))
elif not is_viable_expansion(inst):
continue
else:
for part in inst.parts:
size = part.size
if part.name == "_SAVE_RETURN_OFFSET":
size = OPARG_KINDS["OPARG_SAVE_RETURN_OFFSET"]
if isinstance(part, Uop):
# Skip specializations
if "specializing" in part.annotations:
continue
if "replaced" in part.annotations:
size = OPARG_KINDS["OPARG_REPLACED"]
expansions.append((part.name, size, offset if size else 0))
offset += part.size
expansions_table[inst.name] = expansions
max_uops = max(len(ex) for ex in expansions_table.values())
out.emit(f"#define MAX_UOP_PER_EXPANSION {max_uops}\n")
out.emit("struct opcode_macro_expansion {\n")
out.emit("int nuops;\n")
out.emit(
"struct { int16_t uop; int8_t size; int8_t offset; } uops[MAX_UOP_PER_EXPANSION];\n"
)
out.emit("};\n")
out.emit(
"extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[256];\n\n"
)
out.emit("#ifdef NEED_OPCODE_METADATA\n")
out.emit("const struct opcode_macro_expansion\n")
out.emit("_PyOpcode_macro_expansion[256] = {\n")
for inst_name, expansions in expansions_table.items():
uops = [
f"{{ {name}, {size}, {offset} }}" for (name, size, offset) in expansions
]
out.emit(
f'[{inst_name}] = {{ .nuops = {len(expansions)}, .uops = {{ {", ".join(uops)} }} }},\n'
)
out.emit("};\n")
out.emit("#endif // NEED_OPCODE_METADATA\n\n")
def is_viable_expansion(inst: Instruction) -> bool:
"An instruction can be expanded if all its parts are viable for tier 2"
for part in inst.parts:
if isinstance(part, Uop):
# Skip specializing and replaced uops
if "specializing" in part.annotations:
continue
if "replaced" in part.annotations:
continue
if part.properties.tier_one_only or not part.is_viable():
return False
return True
def generate_extra_cases(analysis: Analysis, out: CWriter) -> None:
out.emit("#define EXTRA_CASES \\\n")
valid_opcodes = set(analysis.opmap.values())
for op in range(256):
if op not in valid_opcodes:
out.emit(f" case {op}: \\\n")
out.emit(" ;\n")
def generate_pseudo_targets(analysis: Analysis, out: CWriter) -> None:
table_size = len(analysis.pseudos)
max_targets = max(len(pseudo.targets) for pseudo in analysis.pseudos.values())
out.emit("struct pseudo_targets {\n")
out.emit(f"uint8_t targets[{max_targets + 1}];\n")
out.emit("};\n")
out.emit(
f"extern const struct pseudo_targets _PyOpcode_PseudoTargets[{table_size}];\n"
)
out.emit("#ifdef NEED_OPCODE_METADATA\n")
out.emit(
f"const struct pseudo_targets _PyOpcode_PseudoTargets[{table_size}] = {{\n"
)
for pseudo in analysis.pseudos.values():
targets = ["0"] * (max_targets + 1)
for i, target in enumerate(pseudo.targets):
targets[i] = target.name
out.emit(f"[{pseudo.name}-256] = {{ {{ {', '.join(targets)} }} }},\n")
out.emit("};\n\n")
out.emit("#endif // NEED_OPCODE_METADATA\n")
out.emit("static inline bool\n")
out.emit("is_pseudo_target(int pseudo, int target) {\n")
out.emit(f"if (pseudo < 256 || pseudo >= {256+table_size}) {{\n")
out.emit(f"return false;\n")
out.emit("}\n")
out.emit(
f"for (int i = 0; _PyOpcode_PseudoTargets[pseudo-256].targets[i]; i++) {{\n"
)
out.emit(
f"if (_PyOpcode_PseudoTargets[pseudo-256].targets[i] == target) return true;\n"
)
out.emit("}\n")
out.emit(f"return false;\n")
out.emit("}\n\n")
def generate_opcode_metadata(
filenames: list[str], analysis: Analysis, outfile: TextIO
) -> None:
write_header(__file__, filenames, outfile)
out = CWriter(outfile, 0, False)
with out.header_guard("Py_CORE_OPCODE_METADATA_H"):
out.emit("#ifndef Py_BUILD_CORE\n")
out.emit('# error "this header requires Py_BUILD_CORE define"\n')
out.emit("#endif\n\n")
out.emit("#include <stdbool.h> // bool\n")
out.emit('#include "opcode_ids.h"\n')
generate_is_pseudo(analysis, out)
out.emit('#include "pycore_uop_ids.h"\n')
generate_stack_effect_functions(analysis, out)
generate_instruction_formats(analysis, out)
table_size = 256 + len(analysis.pseudos)
out.emit("#define IS_VALID_OPCODE(OP) \\\n")
out.emit(f" (((OP) >= 0) && ((OP) < {table_size}) && \\\n")
out.emit(" (_PyOpcode_opcode_metadata[(OP)].valid_entry))\n\n")
generate_flag_macros(out)
generate_oparg_macros(out)
generate_metadata_table(analysis, out)
generate_expansion_table(analysis, out)
generate_name_table(analysis, out)
generate_cache_table(analysis, out)
generate_deopt_table(analysis, out)
generate_extra_cases(analysis, out)
generate_pseudo_targets(analysis, out)
arg_parser = argparse.ArgumentParser(
description="Generate the header file with opcode metadata.",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
DEFAULT_OUTPUT = ROOT / "Include/internal/pycore_uop_metadata.h"
arg_parser.add_argument(
"-o", "--output", type=str, help="Generated code", default=DEFAULT_OUTPUT
)
arg_parser.add_argument(
"input", nargs=argparse.REMAINDER, help="Instruction definition file(s)"
)
if __name__ == "__main__":
args = arg_parser.parse_args()
if len(args.input) == 0:
args.input.append(DEFAULT_INPUT)
data = analyze_files(args.input)
with open(args.output, "w") as outfile:
generate_opcode_metadata(args.input, data, outfile)

View file

@ -0,0 +1,97 @@
"""Generate uop metedata.
Reads the instruction definitions from bytecodes.c.
Writes the metadata to pycore_uop_metadata.h by default.
"""
import argparse
from analyzer import (
Analysis,
analyze_files,
)
from generators_common import (
DEFAULT_INPUT,
ROOT,
root_relative_path,
write_header,
)
from cwriter import CWriter
from typing import TextIO
DEFAULT_OUTPUT = ROOT / "Lib/_opcode_metadata.py"
def get_specialized(analysis: Analysis) -> set[str]:
specialized: set[str] = set()
for family in analysis.families.values():
for member in family.members:
specialized.add(member.name)
return specialized
def generate_specializations(analysis: Analysis, out: CWriter) -> None:
out.emit("_specializations = {\n")
for family in analysis.families.values():
out.emit(f'"{family.name}": [\n')
for member in family.members:
out.emit(f' "{member.name}",\n')
out.emit("],\n")
out.emit("}\n\n")
def generate_specialized_opmap(analysis: Analysis, out: CWriter) -> None:
out.emit("_specialized_opmap = {\n")
names = []
for family in analysis.families.values():
for member in family.members:
if member.name == family.name:
continue
names.append(member.name)
for name in sorted(names):
out.emit(f"'{name}': {analysis.opmap[name]},\n")
out.emit("}\n\n")
def generate_opmap(analysis: Analysis, out: CWriter) -> None:
specialized = get_specialized(analysis)
out.emit("opmap = {\n")
for inst, op in analysis.opmap.items():
if inst not in specialized:
out.emit(f"'{inst}': {analysis.opmap[inst]},\n")
out.emit("}\n\n")
def generate_py_metadata(
filenames: list[str], analysis: Analysis, outfile: TextIO
) -> None:
write_header(__file__, filenames, outfile, "#")
out = CWriter(outfile, 0, False)
generate_specializations(analysis, out)
generate_specialized_opmap(analysis, out)
generate_opmap(analysis, out)
out.emit(f"HAVE_ARGUMENT = {analysis.have_arg}\n")
out.emit(f"MIN_INSTRUMENTED_OPCODE = {analysis.min_instrumented}\n")
arg_parser = argparse.ArgumentParser(
description="Generate the Python file with opcode metadata.",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
arg_parser.add_argument(
"-o", "--output", type=str, help="Generated code", default=DEFAULT_OUTPUT
)
arg_parser.add_argument(
"input", nargs=argparse.REMAINDER, help="Instruction definition file(s)"
)
if __name__ == "__main__":
args = arg_parser.parse_args()
if len(args.input) == 0:
args.input.append(DEFAULT_INPUT)
data = analyze_files(args.input)
with open(args.output, "w") as outfile:
generate_py_metadata(args.input, data, outfile)

View file

@ -1,5 +1,5 @@
import sys import sys
from analyzer import StackItem from analyzer import StackItem, Instruction, Uop
from dataclasses import dataclass from dataclasses import dataclass
from formatting import maybe_parenthesize from formatting import maybe_parenthesize
from cwriter import CWriter from cwriter import CWriter
@ -15,13 +15,16 @@ def var_size(var: StackItem) -> str:
else: else:
return var.size return var.size
@dataclass
class StackOffset: class StackOffset:
"The stack offset of the virtual base of the stack from the physical stack pointer" "The stack offset of the virtual base of the stack from the physical stack pointer"
def __init__(self) -> None: popped: list[str]
self.popped: list[str] = [] pushed: list[str]
self.pushed: list[str] = []
@staticmethod
def empty() -> "StackOffset":
return StackOffset([], [])
def pop(self, item: StackItem) -> None: def pop(self, item: StackItem) -> None:
self.popped.append(var_size(item)) self.popped.append(var_size(item))
@ -29,6 +32,15 @@ class StackOffset:
def push(self, item: StackItem) -> None: def push(self, item: StackItem) -> None:
self.pushed.append(var_size(item)) self.pushed.append(var_size(item))
def __sub__(self, other: "StackOffset") -> "StackOffset":
return StackOffset(
self.popped + other.pushed,
self.pushed + other.popped
)
def __neg__(self) -> "StackOffset":
return StackOffset(self.pushed, self.popped)
def simplify(self) -> None: def simplify(self) -> None:
"Remove matching values from both the popped and pushed list" "Remove matching values from both the popped and pushed list"
if not self.popped or not self.pushed: if not self.popped or not self.pushed:
@ -88,9 +100,9 @@ class SizeMismatch(Exception):
class Stack: class Stack:
def __init__(self) -> None: def __init__(self) -> None:
self.top_offset = StackOffset() self.top_offset = StackOffset.empty()
self.base_offset = StackOffset() self.base_offset = StackOffset.empty()
self.peek_offset = StackOffset() self.peek_offset = StackOffset.empty()
self.variables: list[StackItem] = [] self.variables: list[StackItem] = []
self.defined: set[str] = set() self.defined: set[str] = set()
@ -166,3 +178,15 @@ class Stack:
def as_comment(self) -> str: def as_comment(self) -> str:
return f"/* Variables: {[v.name for v in self.variables]}. Base offset: {self.base_offset.to_c()}. Top offset: {self.top_offset.to_c()} */" return f"/* Variables: {[v.name for v in self.variables]}. Base offset: {self.base_offset.to_c()}. Top offset: {self.top_offset.to_c()} */"
def get_stack_effect(inst: Instruction) -> Stack:
stack = Stack()
for uop in inst.parts:
if not isinstance(uop, Uop):
continue
for var in reversed(uop.stack.inputs):
stack.pop(var)
for i, var in enumerate(uop.stack.outputs):
stack.push(var)
return stack

View file

@ -190,6 +190,7 @@ def generate_tier1_from_files(
with open(outfilename, "w") as outfile: with open(outfilename, "w") as outfile:
generate_tier1(filenames, data, outfile, lines) generate_tier1(filenames, data, outfile, lines)
if __name__ == "__main__": if __name__ == "__main__":
args = arg_parser.parse_args() args = arg_parser.parse_args()
if len(args.input) == 0: if len(args.input) == 0:

View file

@ -103,13 +103,6 @@ TIER2_REPLACEMENT_FUNCTIONS["ERROR_IF"] = tier2_replace_error
TIER2_REPLACEMENT_FUNCTIONS["DEOPT_IF"] = tier2_replace_deopt TIER2_REPLACEMENT_FUNCTIONS["DEOPT_IF"] = tier2_replace_deopt
def is_super(uop: Uop) -> bool:
for tkn in uop.body:
if tkn.kind == "IDENTIFIER" and tkn.text == "oparg1":
return True
return False
def write_uop(uop: Uop, out: CWriter, stack: Stack) -> None: def write_uop(uop: Uop, out: CWriter, stack: Stack) -> None:
try: try:
out.start_line() out.start_line()
@ -156,7 +149,7 @@ def generate_tier2(
for name, uop in analysis.uops.items(): for name, uop in analysis.uops.items():
if uop.properties.tier_one_only: if uop.properties.tier_one_only:
continue continue
if is_super(uop): if uop.is_super():
continue continue
if not uop.is_viable(): if not uop.is_viable():
out.emit(f"/* {uop.name} is not a viable micro-op for tier 2 */\n\n") out.emit(f"/* {uop.name} is not a viable micro-op for tier 2 */\n\n")

View file

@ -24,24 +24,12 @@ from typing import TextIO
DEFAULT_OUTPUT = ROOT / "Include/internal/pycore_uop_ids.h" DEFAULT_OUTPUT = ROOT / "Include/internal/pycore_uop_ids.h"
OMIT = {"_CACHE", "_RESERVED", "_EXTENDED_ARG"}
def generate_uop_ids( def generate_uop_ids(
filenames: list[str], analysis: Analysis, outfile: TextIO, distinct_namespace: bool filenames: list[str], analysis: Analysis, outfile: TextIO, distinct_namespace: bool
) -> None: ) -> None:
write_header(__file__, filenames, outfile) write_header(__file__, filenames, outfile)
out = CWriter(outfile, 0, False) out = CWriter(outfile, 0, False)
out.emit( with out.header_guard("Py_CORE_UOP_IDS_H"):
"""#ifndef Py_CORE_UOP_IDS_H
#define Py_CORE_UOP_IDS_H
#ifdef __cplusplus
extern "C" {
#endif
"""
)
next_id = 1 if distinct_namespace else 300 next_id = 1 if distinct_namespace else 300
# These two are first by convention # These two are first by convention
out.emit(f"#define _EXIT_TRACE {next_id}\n") out.emit(f"#define _EXIT_TRACE {next_id}\n")
@ -53,9 +41,7 @@ extern "C" {
for uop in analysis.uops.values(): for uop in analysis.uops.values():
if uop.name in PRE_DEFINED: if uop.name in PRE_DEFINED:
continue continue
# TODO: We should omit all tier-1 only uops, but if uop.properties.tier_one_only:
# generate_cases.py still generates code for those.
if uop.name in OMIT:
continue continue
if uop.implicitly_created and not distinct_namespace: if uop.implicitly_created and not distinct_namespace:
out.emit(f"#define {uop.name} {uop.name[1:]}\n") out.emit(f"#define {uop.name} {uop.name[1:]}\n")
@ -63,11 +49,7 @@ extern "C" {
out.emit(f"#define {uop.name} {next_id}\n") out.emit(f"#define {uop.name} {next_id}\n")
next_id += 1 next_id += 1
out.emit("\n") out.emit(f"#define MAX_UOP_ID {next_id-1}\n")
out.emit("#ifdef __cplusplus\n")
out.emit("}\n")
out.emit("#endif\n")
out.emit("#endif /* !Py_OPCODE_IDS_H */\n")
arg_parser = argparse.ArgumentParser( arg_parser = argparse.ArgumentParser(

View file

@ -0,0 +1,73 @@
"""Generate uop metedata.
Reads the instruction definitions from bytecodes.c.
Writes the metadata to pycore_uop_metadata.h by default.
"""
import argparse
from analyzer import (
Analysis,
analyze_files,
)
from generators_common import (
DEFAULT_INPUT,
ROOT,
write_header,
cflags,
)
from cwriter import CWriter
from typing import TextIO
DEFAULT_OUTPUT = ROOT / "Include/internal/pycore_uop_metadata.h"
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 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")
for uop in analysis.uops.values():
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 char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = {\n")
for uop in sorted(analysis.uops.values(), key=lambda t: t.name):
if uop.is_viable() and not uop.properties.tier_one_only:
out.emit(f'[{uop.name}] = "{uop.name}",\n')
out.emit("};\n")
out.emit("#endif // NEED_OPCODE_METADATA\n\n")
def generate_uop_metadata(
filenames: list[str], analysis: Analysis, outfile: TextIO
) -> None:
write_header(__file__, filenames, outfile)
out = CWriter(outfile, 0, False)
with out.header_guard("Py_CORE_UOP_METADATA_H"):
out.emit("#include <stdint.h>\n")
out.emit('#include "pycore_uop_ids.h"\n')
generate_names_and_flags(analysis, out)
arg_parser = argparse.ArgumentParser(
description="Generate the header file with uop metadata.",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
arg_parser.add_argument(
"-o", "--output", type=str, help="Generated code", default=DEFAULT_OUTPUT
)
arg_parser.add_argument(
"input", nargs=argparse.REMAINDER, help="Instruction definition file(s)"
)
if __name__ == "__main__":
args = arg_parser.parse_args()
if len(args.input) == 0:
args.input.append(DEFAULT_INPUT)
data = analyze_files(args.input)
with open(args.output, "w") as outfile:
generate_uop_metadata(args.input, data, outfile)