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:
// Python/bytecodes.c
// Do not edit!
#ifndef Py_CORE_UOP_IDS_H
#define Py_CORE_UOP_IDS_H
#ifdef __cplusplus
@ -11,7 +12,6 @@ extern "C" {
#define _EXIT_TRACE 300
#define _SET_IP 301
#define _NOP NOP
#define _RESUME RESUME
#define _RESUME_CHECK RESUME_CHECK
#define _INSTRUMENTED_RESUME INSTRUMENTED_RESUME
#define _LOAD_FAST_CHECK LOAD_FAST_CHECK
@ -24,13 +24,10 @@ extern "C" {
#define _STORE_FAST_STORE_FAST STORE_FAST_STORE_FAST
#define _POP_TOP POP_TOP
#define _PUSH_NULL PUSH_NULL
#define _INSTRUMENTED_END_FOR INSTRUMENTED_END_FOR
#define _END_SEND END_SEND
#define _INSTRUMENTED_END_SEND INSTRUMENTED_END_SEND
#define _UNARY_NEGATIVE UNARY_NEGATIVE
#define _UNARY_NOT UNARY_NOT
#define _SPECIALIZE_TO_BOOL 302
#define _TO_BOOL 303
#define _TO_BOOL 302
#define _TO_BOOL_BOOL TO_BOOL_BOOL
#define _TO_BOOL_INT TO_BOOL_INT
#define _TO_BOOL_LIST TO_BOOL_LIST
@ -38,19 +35,17 @@ extern "C" {
#define _TO_BOOL_STR TO_BOOL_STR
#define _TO_BOOL_ALWAYS_TRUE TO_BOOL_ALWAYS_TRUE
#define _UNARY_INVERT UNARY_INVERT
#define _GUARD_BOTH_INT 304
#define _BINARY_OP_MULTIPLY_INT 305
#define _BINARY_OP_ADD_INT 306
#define _BINARY_OP_SUBTRACT_INT 307
#define _GUARD_BOTH_FLOAT 308
#define _BINARY_OP_MULTIPLY_FLOAT 309
#define _BINARY_OP_ADD_FLOAT 310
#define _BINARY_OP_SUBTRACT_FLOAT 311
#define _GUARD_BOTH_UNICODE 312
#define _BINARY_OP_ADD_UNICODE 313
#define _BINARY_OP_INPLACE_ADD_UNICODE 314
#define _SPECIALIZE_BINARY_SUBSCR 315
#define _BINARY_SUBSCR 316
#define _GUARD_BOTH_INT 303
#define _BINARY_OP_MULTIPLY_INT 304
#define _BINARY_OP_ADD_INT 305
#define _BINARY_OP_SUBTRACT_INT 306
#define _GUARD_BOTH_FLOAT 307
#define _BINARY_OP_MULTIPLY_FLOAT 308
#define _BINARY_OP_ADD_FLOAT 309
#define _BINARY_OP_SUBTRACT_FLOAT 310
#define _GUARD_BOTH_UNICODE 311
#define _BINARY_OP_ADD_UNICODE 312
#define _BINARY_SUBSCR 313
#define _BINARY_SLICE BINARY_SLICE
#define _STORE_SLICE STORE_SLICE
#define _BINARY_SUBSCR_LIST_INT BINARY_SUBSCR_LIST_INT
@ -60,54 +55,43 @@ extern "C" {
#define _BINARY_SUBSCR_GETITEM BINARY_SUBSCR_GETITEM
#define _LIST_APPEND LIST_APPEND
#define _SET_ADD SET_ADD
#define _SPECIALIZE_STORE_SUBSCR 317
#define _STORE_SUBSCR 318
#define _STORE_SUBSCR 314
#define _STORE_SUBSCR_LIST_INT STORE_SUBSCR_LIST_INT
#define _STORE_SUBSCR_DICT STORE_SUBSCR_DICT
#define _DELETE_SUBSCR DELETE_SUBSCR
#define _CALL_INTRINSIC_1 CALL_INTRINSIC_1
#define _CALL_INTRINSIC_2 CALL_INTRINSIC_2
#define _RAISE_VARARGS RAISE_VARARGS
#define _INTERPRETER_EXIT INTERPRETER_EXIT
#define _POP_FRAME 319
#define _POP_FRAME 315
#define _INSTRUMENTED_RETURN_VALUE INSTRUMENTED_RETURN_VALUE
#define _INSTRUMENTED_RETURN_CONST INSTRUMENTED_RETURN_CONST
#define _GET_AITER GET_AITER
#define _GET_ANEXT GET_ANEXT
#define _GET_AWAITABLE GET_AWAITABLE
#define _SPECIALIZE_SEND 320
#define _SEND 321
#define _SEND 316
#define _SEND_GEN SEND_GEN
#define _INSTRUMENTED_YIELD_VALUE INSTRUMENTED_YIELD_VALUE
#define _YIELD_VALUE YIELD_VALUE
#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_BUILD_CLASS LOAD_BUILD_CLASS
#define _STORE_NAME STORE_NAME
#define _DELETE_NAME DELETE_NAME
#define _SPECIALIZE_UNPACK_SEQUENCE 322
#define _UNPACK_SEQUENCE 323
#define _UNPACK_SEQUENCE 317
#define _UNPACK_SEQUENCE_TWO_TUPLE UNPACK_SEQUENCE_TWO_TUPLE
#define _UNPACK_SEQUENCE_TUPLE UNPACK_SEQUENCE_TUPLE
#define _UNPACK_SEQUENCE_LIST UNPACK_SEQUENCE_LIST
#define _UNPACK_EX UNPACK_EX
#define _SPECIALIZE_STORE_ATTR 324
#define _STORE_ATTR 325
#define _STORE_ATTR 318
#define _DELETE_ATTR DELETE_ATTR
#define _STORE_GLOBAL STORE_GLOBAL
#define _DELETE_GLOBAL DELETE_GLOBAL
#define _LOAD_LOCALS LOAD_LOCALS
#define _LOAD_FROM_DICT_OR_GLOBALS LOAD_FROM_DICT_OR_GLOBALS
#define _LOAD_NAME LOAD_NAME
#define _SPECIALIZE_LOAD_GLOBAL 326
#define _LOAD_GLOBAL 327
#define _GUARD_GLOBALS_VERSION 328
#define _GUARD_BUILTINS_VERSION 329
#define _LOAD_GLOBAL_MODULE 330
#define _LOAD_GLOBAL_BUILTINS 331
#define _LOAD_GLOBAL 319
#define _GUARD_GLOBALS_VERSION 320
#define _GUARD_BUILTINS_VERSION 321
#define _LOAD_GLOBAL_MODULE 322
#define _LOAD_GLOBAL_BUILTINS 323
#define _DELETE_FAST DELETE_FAST
#define _MAKE_CELL MAKE_CELL
#define _DELETE_DEREF DELETE_DEREF
@ -128,30 +112,26 @@ extern "C" {
#define _DICT_MERGE DICT_MERGE
#define _MAP_ADD MAP_ADD
#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_METHOD LOAD_SUPER_ATTR_METHOD
#define _SPECIALIZE_LOAD_ATTR 334
#define _LOAD_ATTR 335
#define _GUARD_TYPE_VERSION 336
#define _CHECK_MANAGED_OBJECT_HAS_VALUES 337
#define _LOAD_ATTR_INSTANCE_VALUE 338
#define _CHECK_ATTR_MODULE 339
#define _LOAD_ATTR_MODULE 340
#define _CHECK_ATTR_WITH_HINT 341
#define _LOAD_ATTR_WITH_HINT 342
#define _LOAD_ATTR_SLOT 343
#define _CHECK_ATTR_CLASS 344
#define _LOAD_ATTR_CLASS 345
#define _LOAD_ATTR 324
#define _GUARD_TYPE_VERSION 325
#define _CHECK_MANAGED_OBJECT_HAS_VALUES 326
#define _LOAD_ATTR_INSTANCE_VALUE 327
#define _CHECK_ATTR_MODULE 328
#define _LOAD_ATTR_MODULE 329
#define _CHECK_ATTR_WITH_HINT 330
#define _LOAD_ATTR_WITH_HINT 331
#define _LOAD_ATTR_SLOT 332
#define _CHECK_ATTR_CLASS 333
#define _LOAD_ATTR_CLASS 334
#define _LOAD_ATTR_PROPERTY LOAD_ATTR_PROPERTY
#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN
#define _GUARD_DORV_VALUES 346
#define _STORE_ATTR_INSTANCE_VALUE 347
#define _GUARD_DORV_VALUES 335
#define _STORE_ATTR_INSTANCE_VALUE 336
#define _STORE_ATTR_WITH_HINT STORE_ATTR_WITH_HINT
#define _STORE_ATTR_SLOT 348
#define _SPECIALIZE_COMPARE_OP 349
#define _COMPARE_OP 350
#define _STORE_ATTR_SLOT 337
#define _COMPARE_OP 338
#define _COMPARE_OP_FLOAT COMPARE_OP_FLOAT
#define _COMPARE_OP_INT COMPARE_OP_INT
#define _COMPARE_OP_STR COMPARE_OP_STR
@ -159,15 +139,10 @@ extern "C" {
#define _CONTAINS_OP CONTAINS_OP
#define _CHECK_EG_MATCH CHECK_EG_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 _ENTER_EXECUTOR ENTER_EXECUTOR
#define _POP_JUMP_IF_FALSE 351
#define _POP_JUMP_IF_TRUE 352
#define _IS_NONE 353
#define _JUMP_BACKWARD_NO_INTERRUPT JUMP_BACKWARD_NO_INTERRUPT
#define _POP_JUMP_IF_FALSE 339
#define _POP_JUMP_IF_TRUE 340
#define _IS_NONE 341
#define _GET_LEN GET_LEN
#define _MATCH_CLASS MATCH_CLASS
#define _MATCH_MAPPING MATCH_MAPPING
@ -175,45 +150,43 @@ extern "C" {
#define _MATCH_KEYS MATCH_KEYS
#define _GET_ITER GET_ITER
#define _GET_YIELD_FROM_ITER GET_YIELD_FROM_ITER
#define _SPECIALIZE_FOR_ITER 354
#define _FOR_ITER 355
#define _FOR_ITER_TIER_TWO 356
#define _FOR_ITER 342
#define _FOR_ITER_TIER_TWO 343
#define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER
#define _ITER_CHECK_LIST 357
#define _ITER_JUMP_LIST 358
#define _GUARD_NOT_EXHAUSTED_LIST 359
#define _ITER_NEXT_LIST 360
#define _ITER_CHECK_TUPLE 361
#define _ITER_JUMP_TUPLE 362
#define _GUARD_NOT_EXHAUSTED_TUPLE 363
#define _ITER_NEXT_TUPLE 364
#define _ITER_CHECK_RANGE 365
#define _ITER_JUMP_RANGE 366
#define _GUARD_NOT_EXHAUSTED_RANGE 367
#define _ITER_NEXT_RANGE 368
#define _ITER_CHECK_LIST 344
#define _ITER_JUMP_LIST 345
#define _GUARD_NOT_EXHAUSTED_LIST 346
#define _ITER_NEXT_LIST 347
#define _ITER_CHECK_TUPLE 348
#define _ITER_JUMP_TUPLE 349
#define _GUARD_NOT_EXHAUSTED_TUPLE 350
#define _ITER_NEXT_TUPLE 351
#define _ITER_CHECK_RANGE 352
#define _ITER_JUMP_RANGE 353
#define _GUARD_NOT_EXHAUSTED_RANGE 354
#define _ITER_NEXT_RANGE 355
#define _FOR_ITER_GEN FOR_ITER_GEN
#define _BEFORE_ASYNC_WITH BEFORE_ASYNC_WITH
#define _BEFORE_WITH BEFORE_WITH
#define _WITH_EXCEPT_START WITH_EXCEPT_START
#define _PUSH_EXC_INFO PUSH_EXC_INFO
#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 369
#define _GUARD_KEYS_VERSION 370
#define _LOAD_ATTR_METHOD_WITH_VALUES 371
#define _LOAD_ATTR_METHOD_NO_DICT 372
#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 373
#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 374
#define _CHECK_ATTR_METHOD_LAZY_DICT 375
#define _LOAD_ATTR_METHOD_LAZY_DICT 376
#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 356
#define _GUARD_KEYS_VERSION 357
#define _LOAD_ATTR_METHOD_WITH_VALUES 358
#define _LOAD_ATTR_METHOD_NO_DICT 359
#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 360
#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 361
#define _CHECK_ATTR_METHOD_LAZY_DICT 362
#define _LOAD_ATTR_METHOD_LAZY_DICT 363
#define _INSTRUMENTED_CALL INSTRUMENTED_CALL
#define _SPECIALIZE_CALL 377
#define _CALL 378
#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 379
#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 380
#define _CHECK_PEP_523 381
#define _CHECK_FUNCTION_EXACT_ARGS 382
#define _CHECK_STACK_SPACE 383
#define _INIT_CALL_PY_EXACT_ARGS 384
#define _PUSH_FRAME 385
#define _CALL 364
#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 365
#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 366
#define _CHECK_PEP_523 367
#define _CHECK_FUNCTION_EXACT_ARGS 368
#define _CHECK_STACK_SPACE 369
#define _INIT_CALL_PY_EXACT_ARGS 370
#define _PUSH_FRAME 371
#define _CALL_PY_WITH_DEFAULTS CALL_PY_WITH_DEFAULTS
#define _CALL_TYPE_1 CALL_TYPE_1
#define _CALL_STR_1 CALL_STR_1
@ -226,7 +199,6 @@ extern "C" {
#define _CALL_BUILTIN_FAST_WITH_KEYWORDS CALL_BUILTIN_FAST_WITH_KEYWORDS
#define _CALL_LEN CALL_LEN
#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_FAST_WITH_KEYWORDS CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS
#define _CALL_METHOD_DESCRIPTOR_NOARGS CALL_METHOD_DESCRIPTOR_NOARGS
@ -237,14 +209,12 @@ extern "C" {
#define _CALL_FUNCTION_EX CALL_FUNCTION_EX
#define _MAKE_FUNCTION MAKE_FUNCTION
#define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE
#define _RETURN_GENERATOR RETURN_GENERATOR
#define _BUILD_SLICE BUILD_SLICE
#define _CONVERT_VALUE CONVERT_VALUE
#define _FORMAT_SIMPLE FORMAT_SIMPLE
#define _FORMAT_WITH_SPEC FORMAT_WITH_SPEC
#define _COPY COPY
#define _SPECIALIZE_BINARY_OP 386
#define _BINARY_OP 387
#define _BINARY_OP 372
#define _SWAP SWAP
#define _INSTRUMENTED_INSTRUCTION INSTRUMENTED_INSTRUCTION
#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_NONE INSTRUMENTED_POP_JUMP_IF_NONE
#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE INSTRUMENTED_POP_JUMP_IF_NOT_NONE
#define _GUARD_IS_TRUE_POP 388
#define _GUARD_IS_FALSE_POP 389
#define _GUARD_IS_NONE_POP 390
#define _GUARD_IS_NOT_NONE_POP 391
#define _JUMP_TO_TOP 392
#define _SAVE_RETURN_OFFSET 393
#define _INSERT 394
#define _CHECK_VALIDITY 395
#define _GUARD_IS_TRUE_POP 373
#define _GUARD_IS_FALSE_POP 374
#define _GUARD_IS_NONE_POP 375
#define _GUARD_IS_NOT_NONE_POP 376
#define _JUMP_TO_TOP 377
#define _SAVE_RETURN_OFFSET 378
#define _INSERT 379
#define _CHECK_VALIDITY 380
#define MAX_UOP_ID 380
#ifdef __cplusplus
}
#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 STORE_FAST_MAYBE_NULL 267
#define HAVE_ARGUMENT 45
#define HAVE_ARGUMENT 44
#define MIN_INSTRUMENTED_OPCODE 236
#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:
# Python/bytecodes.c
# Do not edit!
_specializations = {
"RESUME": [
"RESUME_CHECK",
@ -23,6 +22,7 @@ _specializations = {
"BINARY_OP_ADD_FLOAT",
"BINARY_OP_SUBTRACT_FLOAT",
"BINARY_OP_ADD_UNICODE",
"BINARY_OP_INPLACE_ADD_UNICODE",
],
"BINARY_SUBSCR": [
"BINARY_SUBSCR_DICT",
@ -103,14 +103,11 @@ _specializations = {
],
}
# An irregular case:
_specializations["BINARY_OP"].append("BINARY_OP_INPLACE_ADD_UNICODE")
_specialized_opmap = {
'BINARY_OP_INPLACE_ADD_UNICODE': 3,
'BINARY_OP_ADD_FLOAT': 150,
'BINARY_OP_ADD_INT': 151,
'BINARY_OP_ADD_UNICODE': 152,
'BINARY_OP_INPLACE_ADD_UNICODE': 3,
'BINARY_OP_MULTIPLY_FLOAT': 153,
'BINARY_OP_MULTIPLY_INT': 154,
'BINARY_OP_SUBTRACT_FLOAT': 155,
@ -181,6 +178,9 @@ _specialized_opmap = {
opmap = {
'CACHE': 0,
'RESERVED': 17,
'RESUME': 149,
'INSTRUMENTED_LINE': 254,
'BEFORE_ASYNC_WITH': 1,
'BEFORE_WITH': 2,
'BINARY_SLICE': 4,
@ -196,7 +196,6 @@ opmap = {
'FORMAT_SIMPLE': 14,
'FORMAT_WITH_SPEC': 15,
'GET_AITER': 16,
'RESERVED': 17,
'GET_ANEXT': 18,
'GET_ITER': 19,
'GET_LEN': 20,
@ -298,7 +297,6 @@ opmap = {
'UNPACK_EX': 116,
'UNPACK_SEQUENCE': 117,
'YIELD_VALUE': 118,
'RESUME': 149,
'INSTRUMENTED_RESUME': 236,
'INSTRUMENTED_END_FOR': 237,
'INSTRUMENTED_END_SEND': 238,
@ -317,7 +315,6 @@ opmap = {
'INSTRUMENTED_POP_JUMP_IF_FALSE': 251,
'INSTRUMENTED_POP_JUMP_IF_NONE': 252,
'INSTRUMENTED_POP_JUMP_IF_NOT_NONE': 253,
'INSTRUMENTED_LINE': 254,
'JUMP': 256,
'JUMP_NO_INTERRUPT': 257,
'LOAD_CLOSURE': 258,
@ -331,5 +328,6 @@ opmap = {
'SETUP_WITH': 266,
'STORE_FAST_MAYBE_NULL': 267,
}
HAVE_ARGUMENT = 44
MIN_INSTRUMENTED_OPCODE = 236
HAVE_ARGUMENT = 45

View file

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

View file

@ -1588,23 +1588,28 @@ regen-cases:
$(srcdir)/Tools/cases_generator/generate_cases.py \
$(CASESFLAG) \
-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 \
$(srcdir)/Python/bytecodes.c
$(PYTHON_FOR_REGEN) \
$(srcdir)/Tools/cases_generator/opcode_id_generator.py -o $(srcdir)/Include/opcode_ids.h.new $(srcdir)/Python/bytecodes.c
$(PYTHON_FOR_REGEN) \
$(srcdir)/Tools/cases_generator/uop_id_generator.py -o $(srcdir)/Include/internal/pycore_uop_ids.h.new $(srcdir)/Python/bytecodes.c
$(PYTHON_FOR_REGEN) \
$(srcdir)/Tools/cases_generator/tier1_generator.py -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_id_generator.py \
-o $(srcdir)/Include/opcode_ids.h.new $(srcdir)/Python/bytecodes.c
$(PYTHON_FOR_REGEN) $(srcdir)/Tools/cases_generator/uop_id_generator.py \
-o $(srcdir)/Include/internal/pycore_uop_ids.h.new $(srcdir)/Python/bytecodes.c
$(PYTHON_FOR_REGEN) $(srcdir)/Tools/cases_generator/py_metadata_generator.py \
-o $(srcdir)/Lib/_opcode_metadata.py.new $(srcdir)/Python/bytecodes.c
$(PYTHON_FOR_REGEN) $(srcdir)/Tools/cases_generator/tier1_generator.py \
-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)/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)/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_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/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

View file

@ -4,7 +4,7 @@
#include "pycore_code.h" // write_location_entry_start()
#include "pycore_compile.h"
#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
@ -710,13 +710,13 @@ resolve_unconditional_jumps(instr_sequence *instrs)
bool is_forward = (instr->i_oparg > i);
switch(instr->i_opcode) {
case JUMP:
assert(SAME_OPCODE_METADATA(JUMP, JUMP_FORWARD));
assert(SAME_OPCODE_METADATA(JUMP, JUMP_BACKWARD));
assert(is_pseudo_target(JUMP, JUMP_FORWARD));
assert(is_pseudo_target(JUMP, JUMP_BACKWARD));
instr->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD;
break;
case JUMP_NO_INTERRUPT:
assert(SAME_OPCODE_METADATA(JUMP_NO_INTERRUPT, JUMP_FORWARD));
assert(SAME_OPCODE_METADATA(JUMP_NO_INTERRUPT, JUMP_BACKWARD_NO_INTERRUPT));
assert(is_pseudo_target(JUMP_NO_INTERRUPT, JUMP_FORWARD));
assert(is_pseudo_target(JUMP_NO_INTERRUPT, JUMP_BACKWARD_NO_INTERRUPT));
instr->i_opcode = is_forward ?
JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT;
break;

View file

@ -330,14 +330,14 @@ dummy_func(
#endif /* ENABLE_SPECIALIZATION */
}
op(_TO_BOOL, (unused/2, value -- res)) {
op(_TO_BOOL, (value -- res)) {
int err = PyObject_IsTrue(value);
DECREF_INPUTS();
ERROR_IF(err < 0, error);
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)) {
DEOPT_IF(!PyBool_Check(value));
@ -416,7 +416,7 @@ dummy_func(
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);
res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right);
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
@ -424,7 +424,7 @@ dummy_func(
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);
res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right);
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
@ -432,7 +432,7 @@ dummy_func(
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);
res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right);
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
@ -441,18 +441,18 @@ dummy_func(
}
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) =
_GUARD_BOTH_INT + _BINARY_OP_ADD_INT;
_GUARD_BOTH_INT + unused/1 + _BINARY_OP_ADD_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)) {
DEOPT_IF(!PyFloat_CheckExact(left));
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);
double dres =
((PyFloatObject *)left)->ob_fval *
@ -460,7 +460,7 @@ dummy_func(
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);
double dres =
((PyFloatObject *)left)->ob_fval +
@ -468,7 +468,7 @@ dummy_func(
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);
double dres =
((PyFloatObject *)left)->ob_fval -
@ -477,18 +477,18 @@ dummy_func(
}
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) =
_GUARD_BOTH_FLOAT + _BINARY_OP_ADD_FLOAT;
_GUARD_BOTH_FLOAT + unused/1 + _BINARY_OP_ADD_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)) {
DEOPT_IF(!PyUnicode_CheckExact(left));
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);
res = PyUnicode_Concat(left, right);
_Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc);
@ -497,7 +497,7 @@ dummy_func(
}
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
// 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
// specializations, but there is no output.
// 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
assert(next_instr->op.code == STORE_FAST);
PyObject **target_local = &GETLOCAL(next_instr->op.arg);
@ -533,7 +533,7 @@ dummy_func(
}
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) = {
BINARY_SUBSCR_DICT,
@ -1295,14 +1295,14 @@ dummy_func(
#endif /* ENABLE_SPECIALIZATION */
}
op(_STORE_ATTR, (unused/3, v, owner --)) {
op(_STORE_ATTR, (v, owner --)) {
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
int err = PyObject_SetAttr(owner, name, v);
DECREF_INPUTS();
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 --)) {
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
@ -1414,7 +1414,7 @@ dummy_func(
#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);
if (PyDict_CheckExact(GLOBALS())
&& PyDict_CheckExact(BUILTINS()))
@ -1451,7 +1451,12 @@ dummy_func(
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 --)) {
PyDictObject *dict = (PyDictObject *)GLOBALS();
@ -1853,7 +1858,7 @@ dummy_func(
#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);
if (oparg & 1) {
/* 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) = {
LOAD_ATTR,
@ -2369,7 +2377,7 @@ dummy_func(
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));
int flag = Py_IsFalse(cond);
#if ENABLE_SPECIALIZATION
@ -2378,7 +2386,7 @@ dummy_func(
JUMPBY(oparg * flag);
}
replaced op(_POP_JUMP_IF_TRUE, (unused/1, cond -- )) {
replaced op(_POP_JUMP_IF_TRUE, (cond -- )) {
assert(PyBool_Check(cond));
int flag = Py_IsTrue(cond);
#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, (--)) {
TIER_ONE_ONLY
@ -3010,7 +3018,7 @@ dummy_func(
}
// 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:
int total_args = oparg;
if (self_or_null != NULL) {
@ -3079,7 +3087,7 @@ dummy_func(
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])) {
DEOPT_IF(null != NULL);

View file

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

View file

@ -796,35 +796,12 @@ stack_effect(int opcode, int oparg, int jump)
// Specialized instructions are not supported.
return PY_INVALID_STACK_EFFECT;
}
int popped, pushed;
if (jump > 0) {
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);
}
int popped = _PyOpcode_num_popped(opcode, oparg);
int pushed = _PyOpcode_num_pushed(opcode, oparg);
if (popped < 0 || pushed < 0) {
return PY_INVALID_STACK_EFFECT;
}
if (jump >= 0) {
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;
}
return pushed - popped;
}
// Pseudo ops
@ -1125,7 +1102,7 @@ compiler_addop_name(struct compiler_unit *u, location loc,
arg <<= 1;
}
if (opcode == LOAD_METHOD) {
assert(SAME_OPCODE_METADATA(LOAD_METHOD, LOAD_ATTR));
assert(is_pseudo_target(LOAD_METHOD, LOAD_ATTR));
opcode = LOAD_ATTR;
arg <<= 1;
arg |= 1;
@ -1135,18 +1112,18 @@ compiler_addop_name(struct compiler_unit *u, location loc,
arg |= 2;
}
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;
arg <<= 2;
arg |= 3;
}
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;
arg <<= 2;
}
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;
arg <<= 2;
arg |= 1;

View file

@ -2258,11 +2258,11 @@ convert_pseudo_ops(basicblock *entryblock)
INSTR_SET_OP0(instr, NOP);
}
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;
}
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;
}
}

View file

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

View file

@ -6,14 +6,20 @@
#include "pycore_opcode_utils.h" // MAX_REAL_OPCODE
#include "pycore_optimizer.h" // _Py_uop_analyze_and_optimize()
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_uop_ids.h"
#include "pycore_uops.h"
#include "cpython/optimizer.h"
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#define NEED_OPCODE_METADATA
#include "pycore_uop_metadata.h" // Uop tables
#undef NEED_OPCODE_METADATA
#define MAX_EXECUTORS_SIZE 256
static bool
has_space_for_executor(PyCodeObject *code, _Py_CODEUNIT *instr)
{
@ -327,9 +333,6 @@ uop_dealloc(_PyUOpExecutorObject *self) {
const char *
_PyUOpName(int index)
{
if (index <= MAX_REAL_OPCODE) {
return _PyOpcode_OpName[index];
}
return _PyOpcode_uop_name[index];
}
@ -388,7 +391,7 @@ PyTypeObject _PyUOpExecutor_Type = {
/* TO DO -- Generate these tables */
static const uint16_t
_PyUOp_Replacements[OPCODE_METADATA_SIZE] = {
_PyUOp_Replacements[MAX_UOP_ID + 1] = {
[_ITER_JUMP_RANGE] = _GUARD_NOT_EXHAUSTED_RANGE,
[_ITER_JUMP_LIST] = _GUARD_NOT_EXHAUSTED_LIST,
[_ITER_JUMP_TUPLE] = _GUARD_NOT_EXHAUSTED_TUPLE,
@ -629,14 +632,6 @@ translate_bytecode_to_trace(
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;
case OPARG_CACHE_1:
operand = read_u16(&instr[offset].cache);
@ -657,7 +652,15 @@ translate_bytecode_to_trace(
oparg = offset;
assert(uop == _SAVE_RETURN_OFFSET);
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:
fprintf(stderr,
"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 */
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 */
SET_BIT(used, buffer[i].oparg);
}

View file

@ -10,6 +10,7 @@
#include "pycore_moduleobject.h"
#include "pycore_object.h"
#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_pylifecycle.h" // _PyOS_URandomNonblock()
#include "pycore_runtime.h" // _Py_ID()

View file

@ -11,11 +11,16 @@ class Properties:
deopts: bool
oparg: bool
jumps: bool
eval_breaker: bool
ends_with_eval_breaker: bool
needs_this: bool
always_exits: bool
stores_sp: 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:
print(indent, end="")
@ -30,11 +35,16 @@ def from_list(properties: list["Properties"]) -> "Properties":
deopts=any(p.deopts for p in properties),
oparg=any(p.oparg 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),
needs_this=any(p.needs_this for p in properties),
always_exits=any(p.always_exits 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),
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 @@ def from_list(properties: list["Properties"]) -> "Properties":
deopts=False,
oparg=False,
jumps=False,
eval_breaker=False,
ends_with_eval_breaker=False,
needs_this=False,
always_exits=False,
stores_sp=False,
tier_one_only=False,
uses_co_consts=False,
uses_co_names=False,
uses_locals=False,
has_free=False,
)
@ -142,6 +157,12 @@ def is_viable(self) -> bool:
return False
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
@ -153,6 +174,7 @@ class Instruction:
_properties: Properties | None
is_target: bool = False
family: Optional["Family"] = None
opcode: int = -1
@property
def properties(self) -> Properties:
@ -171,16 +193,30 @@ def dump(self, indent: str) -> None:
def size(self) -> int:
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
class PseudoInstruction:
name: str
targets: list[Instruction]
flags: list[str]
opcode: int = -1
def dump(self, indent: str) -> None:
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
class Family:
@ -198,12 +234,15 @@ class Analysis:
uops: dict[str, Uop]
families: dict[str, Family]
pseudos: dict[str, PseudoInstruction]
opmap: dict[str, int]
have_arg: int
min_instrumented: int
def analysis_error(message: str, tkn: lexer.Token) -> SyntaxError:
# To do -- support file and line output
# 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(
@ -238,6 +277,11 @@ def analyze_caches(inputs: list[parser.InputEffect]) -> list[CacheEntry]:
caches: list[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]
@ -300,17 +344,28 @@ def always_exits(op: parser.InstDef) -> bool:
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(
escapes=makes_escaping_api_call(op),
infallible=is_infallible(op),
deopts=variable_used(op, "DEOPT_IF"),
oparg=variable_used(op, "oparg"),
jumps=variable_used(op, "JUMPBY"),
eval_breaker=variable_used(op, "CHECK_EVAL_BREAKER"),
ends_with_eval_breaker=eval_breaker_at_end(op),
needs_this=variable_used(op, "this_instr"),
always_exits=always_exits(op),
stores_sp=variable_used(op, "STORE_SP"),
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:
instructions: dict[str, Instruction] = {}
uops: dict[str, Uop] = {}
@ -460,10 +604,20 @@ def analyze_forest(forest: list[parser.AstNode]) -> Analysis:
continue
if target.text in instructions:
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:
instructions["BINARY_OP_INPLACE_ADD_UNICODE"].family = families["BINARY_OP"]
return Analysis(instructions, uops, families, pseudos)
inst = instructions["BINARY_OP_INPLACE_ADD_UNICODE"]
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:

View file

@ -1,5 +1,6 @@
import contextlib
from lexer import Token
from typing import TextIO
from typing import TextIO, Iterator
class CWriter:
@ -44,9 +45,12 @@ def maybe_dedent(self, txt: str) -> None:
def maybe_indent(self, txt: str) -> None:
parens = txt.count("(") - txt.count(")")
if parens > 0 and self.last_token:
offset = self.last_token.end_column - 1
if offset <= self.indents[-1] or offset > 40:
if parens > 0:
if self.last_token:
offset = self.last_token.end_column - 1
if offset <= self.indents[-1] or offset > 40:
offset = self.indents[-1] + 4
else:
offset = self.indents[-1] + 4
self.indents.append(offset)
if is_label(txt):
@ -54,6 +58,7 @@ def maybe_indent(self, txt: str) -> None:
else:
braces = txt.count("{") - txt.count("}")
if braces > 0:
assert braces == 1
if 'extern "C"' in txt:
self.indents.append(self.indents[-1])
else:
@ -114,6 +119,28 @@ def start_line(self) -> None:
self.newline = True
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:
return not txt.startswith("//") and txt.endswith(":")

View file

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

View file

@ -2,14 +2,11 @@
from typing import TextIO
from analyzer import (
Analysis,
Instruction,
Uop,
Part,
analyze_files,
Properties,
Skip,
StackItem,
analysis_error,
)
from cwriter import CWriter
from typing import Callable, Mapping, TextIO, Iterator
@ -25,14 +22,16 @@ def root_relative_path(filename: str) -> str:
try:
return Path(filename).absolute().relative_to(ROOT).as_posix()
except ValueError:
# Not relative to root, just return original path.
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(
f"""// This file is generated by {root_relative_path(generator)}
// from:
// {", ".join(root_relative_path(src) for src in sources)}
// Do not edit!
f"""{comment} This file is generated by {root_relative_path(generator)}
{comment} from:
{comment} {", ".join(root_relative_path(src) for src in sources)}
{comment} Do not edit!
"""
)
@ -186,3 +185,31 @@ def emit_tokens(
replacement_functions[tkn.text](out, tkn, tkn_iter, uop, stack, inst)
else:
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 @@
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)
out = CWriter(outfile, 0, False)
out.emit("\n")
instmap: dict[str, int] = {}
with out.header_guard("Py_OPCODE_IDS_H"):
out.emit("/* Instruction opcodes for compiled code */\n")
# 0 is reserved for cache entries. This helps debugging.
instmap["CACHE"] = 0
def write_define(name: str, op: int) -> None:
out.emit(f"#define {name:<38} {op:>3}\n")
# 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
for op, name in sorted([(op, name) for (name, op) in analysis.opmap.items()]):
write_define(name, op)
# 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:
out.emit(f"#define {name:<38} {op:>3}\n")
for op, name in sorted([(op, name) for (name, op) in instmap.items()]):
write_define(name, op)
out.emit("\n")
write_define("HAVE_ARGUMENT", len(no_arg))
write_define("MIN_INSTRUMENTED_OPCODE", 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")
out.emit("\n")
write_define("HAVE_ARGUMENT", analysis.have_arg)
write_define("MIN_INSTRUMENTED_OPCODE", analysis.min_instrumented)
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
from analyzer import StackItem
from analyzer import StackItem, Instruction, Uop
from dataclasses import dataclass
from formatting import maybe_parenthesize
from cwriter import CWriter
@ -15,13 +15,16 @@ def var_size(var: StackItem) -> str:
else:
return var.size
@dataclass
class StackOffset:
"The stack offset of the virtual base of the stack from the physical stack pointer"
def __init__(self) -> None:
self.popped: list[str] = []
self.pushed: list[str] = []
popped: list[str]
pushed: list[str]
@staticmethod
def empty() -> "StackOffset":
return StackOffset([], [])
def pop(self, item: StackItem) -> None:
self.popped.append(var_size(item))
@ -29,6 +32,15 @@ def pop(self, item: StackItem) -> None:
def push(self, item: StackItem) -> None:
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:
"Remove matching values from both the popped and pushed list"
if not self.popped or not self.pushed:
@ -88,9 +100,9 @@ class SizeMismatch(Exception):
class Stack:
def __init__(self) -> None:
self.top_offset = StackOffset()
self.base_offset = StackOffset()
self.peek_offset = StackOffset()
self.top_offset = StackOffset.empty()
self.base_offset = StackOffset.empty()
self.peek_offset = StackOffset.empty()
self.variables: list[StackItem] = []
self.defined: set[str] = set()
@ -166,3 +178,15 @@ def flush(self, out: CWriter) -> None:
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()} */"
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:
generate_tier1(filenames, data, outfile, lines)
if __name__ == "__main__":
args = arg_parser.parse_args()
if len(args.input) == 0:

View file

@ -103,13 +103,6 @@ def 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:
try:
out.start_line()
@ -123,7 +116,7 @@ def write_uop(uop: Uop, out: CWriter, stack: Stack) -> None:
for cache in uop.caches:
if cache.name != "unused":
if cache.size == 4:
type = cast ="PyObject *"
type = cast = "PyObject *"
else:
type = f"uint{cache.size*16}_t "
cast = f"uint{cache.size*16}_t"
@ -156,7 +149,7 @@ def generate_tier2(
for name, uop in analysis.uops.items():
if uop.properties.tier_one_only:
continue
if is_super(uop):
if uop.is_super():
continue
if not uop.is_viable():
out.emit(f"/* {uop.name} is not a viable micro-op for tier 2 */\n\n")

View file

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