From 169e08dab65ba5c4b65f28bec23e5acf03c770d0 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 6 Feb 2024 12:57:12 +0800 Subject: [PATCH 01/52] bring over changes from old branch --- .gitattributes | 1 + Include/cpython/pystats.h | 8 + Include/internal/pycore_function.h | 2 +- Include/internal/pycore_opcode_metadata.h | 16 +- Include/internal/pycore_optimizer.h | 11 + Include/internal/pycore_uop_ids.h | 21 +- Include/internal/pycore_uop_metadata.h | 494 +++- Lib/test/test_capi/test_mem.py | 5 + Lib/test/test_capi/test_opt.py | 395 +++- Makefile.pre.in | 6 +- ...-01-16-14-41-54.gh-issue-114058.Cb2b8h.rst | 1 + Python/abstract_interp_cases.c.h | 1997 +++++++++++++++++ Python/bytecodes.c | 28 +- Python/executor_cases.c.h | 24 +- Python/generated_cases.c.h | 2 +- Python/jit.c | 19 +- Python/optimizer.c | 66 +- Python/optimizer_analysis.c | 1078 ++++++++- Python/pylifecycle.c | 1 + Python/specialize.c | 15 + Tools/c-analyzer/cpython/_parser.py | 1 + Tools/c-analyzer/cpython/ignored.tsv | 2 +- Tools/cases_generator/analyzer.py | 7 +- Tools/cases_generator/generators_common.py | 6 +- .../cases_generator/interpreter_definition.md | 3 +- .../opcode_metadata_generator.py | 3 +- Tools/cases_generator/stack.py | 6 +- .../cases_generator/tier2_abstract_common.py | 34 + .../tier2_abstract_generator.py | 435 ++++ .../cases_generator/uop_metadata_generator.py | 21 + 30 files changed, 4563 insertions(+), 145 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-01-16-14-41-54.gh-issue-114058.Cb2b8h.rst create mode 100644 Python/abstract_interp_cases.c.h create mode 100644 Tools/cases_generator/tier2_abstract_common.py create mode 100644 Tools/cases_generator/tier2_abstract_generator.py diff --git a/.gitattributes b/.gitattributes index 2a48df079e1aeb..22afffb05abb20 100644 --- a/.gitattributes +++ b/.gitattributes @@ -94,6 +94,7 @@ Programs/test_frozenmain.h generated Python/Python-ast.c generated Python/executor_cases.c.h generated Python/generated_cases.c.h generated +Python/abstract_interp_cases.c.h generated Python/opcode_targets.h generated Python/stdlib_module_names.h generated Tools/peg_generator/pegen/grammar_parser.py generated diff --git a/Include/cpython/pystats.h b/Include/cpython/pystats.h index bf0cfe4cb695b4..9f3ceb497e5fa6 100644 --- a/Include/cpython/pystats.h +++ b/Include/cpython/pystats.h @@ -120,6 +120,14 @@ typedef struct _optimization_stats { uint64_t trace_length_hist[_Py_UOP_HIST_SIZE]; uint64_t trace_run_length_hist[_Py_UOP_HIST_SIZE]; uint64_t optimized_trace_length_hist[_Py_UOP_HIST_SIZE]; + uint64_t optimizer_attempts; + uint64_t optimizer_successes; + uint64_t optimizer_failure_reason_null_function; + uint64_t optimizer_failure_reason_no_memory; + uint64_t optimizer_failure_reason_no_writebuffer; + uint64_t loop_body_duplication_attempts; + uint64_t loop_body_duplication_successes; + uint64_t loop_body_duplication_no_mem; } OptimizationStats; typedef struct _rare_event_stats { diff --git a/Include/internal/pycore_function.h b/Include/internal/pycore_function.h index 3f3da8a44b77e4..b3f88befb5c540 100644 --- a/Include/internal/pycore_function.h +++ b/Include/internal/pycore_function.h @@ -16,7 +16,7 @@ extern PyObject* _PyFunction_Vectorcall( #define FUNC_MAX_WATCHERS 8 -#define FUNC_VERSION_CACHE_SIZE (1<<12) /* Must be a power of 2 */ +#define FUNC_VERSION_CACHE_SIZE (1<<14) /* Must be a power of 2 */ struct _py_func_state { uint32_t next_version; // Borrowed references to function objects whose diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 75d7f44025328e..87c1150befa903 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -910,7 +910,8 @@ enum InstructionFormat { #define HAS_ERROR_FLAG (256) #define HAS_ESCAPES_FLAG (512) #define HAS_PURE_FLAG (1024) -#define HAS_PASSTHROUGH_FLAG (2048) +#define HAS_GUARD_FLAG (2048) +#define HAS_SPECIAL_OPT_FLAG (4096) #define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ARG_FLAG)) #define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_CONST_FLAG)) #define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NAME_FLAG)) @@ -922,7 +923,8 @@ enum InstructionFormat { #define OPCODE_HAS_ERROR(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ERROR_FLAG)) #define OPCODE_HAS_ESCAPES(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ESCAPES_FLAG)) #define OPCODE_HAS_PURE(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_PURE_FLAG)) -#define OPCODE_HAS_PASSTHROUGH(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_PASSTHROUGH_FLAG)) +#define OPCODE_HAS_GUARD(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_GUARD_FLAG)) +#define OPCODE_HAS_SPECIAL_OPT(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_SPECIAL_OPT_FLAG)) #define OPARG_FULL 0 #define OPARG_CACHE_1 1 @@ -1094,7 +1096,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [MATCH_KEYS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [MATCH_MAPPING] = { true, INSTR_FMT_IX, 0 }, [MATCH_SEQUENCE] = { true, INSTR_FMT_IX, 0 }, - [NOP] = { true, INSTR_FMT_IX, 0 }, + [NOP] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, [POP_EXCEPT] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, @@ -1156,10 +1158,10 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [LOAD_SUPER_METHOD] = { true, -1, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_ZERO_SUPER_ATTR] = { true, -1, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_ZERO_SUPER_METHOD] = { true, -1, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [POP_BLOCK] = { true, -1, 0 }, - [SETUP_CLEANUP] = { true, -1, HAS_ARG_FLAG }, - [SETUP_FINALLY] = { true, -1, HAS_ARG_FLAG }, - [SETUP_WITH] = { true, -1, HAS_ARG_FLAG }, + [POP_BLOCK] = { true, -1, HAS_PURE_FLAG }, + [SETUP_CLEANUP] = { true, -1, HAS_PURE_FLAG | HAS_ARG_FLAG }, + [SETUP_FINALLY] = { true, -1, HAS_PURE_FLAG | HAS_ARG_FLAG }, + [SETUP_WITH] = { true, -1, HAS_PURE_FLAG | HAS_ARG_FLAG }, [STORE_FAST_MAYBE_NULL] = { true, -1, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, }; #endif diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index e21412fc815540..a8ee8f29a73b22 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -8,10 +8,21 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_uop_ids.h" + +// This is the length of the trace we project initially. +#define UOP_MAX_TRACE_LENGTH 512 +// This the above + additional working space we need. +#define UOP_MAX_TRACE_WORKING_LENGTH (UOP_MAX_TRACE_LENGTH * 2) + +#define TRACE_STACK_SIZE 5 + int _Py_uop_analyze_and_optimize(_PyInterpreterFrame *frame, _PyUOpInstruction *trace, int trace_len, int curr_stackentries, _PyBloomFilter *dependencies); + + extern PyTypeObject _PyCounterExecutor_Type; extern PyTypeObject _PyCounterOptimizer_Type; extern PyTypeObject _PyDefaultOptimizer_Type; diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index b2476e1c6e5c4b..c5ecf99905b865 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -229,15 +229,18 @@ extern "C" { #define _GUARD_IS_NOT_NONE_POP 376 #define _JUMP_TO_TOP 377 #define _SAVE_RETURN_OFFSET 378 -#define _CHECK_VALIDITY 379 -#define _LOAD_CONST_INLINE 380 -#define _LOAD_CONST_INLINE_BORROW 381 -#define _LOAD_CONST_INLINE_WITH_NULL 382 -#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 383 -#define _CHECK_GLOBALS 384 -#define _CHECK_BUILTINS 385 -#define _INTERNAL_INCREMENT_OPT_COUNTER 386 -#define MAX_UOP_ID 386 +#define _JUMP_ABSOLUTE 379 +#define _JUMP_ABSOLUTE_HEADER 380 +#define _CHECK_VALIDITY 381 +#define _LOAD_CONST_INLINE 382 +#define _LOAD_CONST_INLINE_BORROW 383 +#define _LOAD_CONST_INLINE_WITH_NULL 384 +#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 385 +#define _CHECK_GLOBALS 386 +#define _CHECK_BUILTINS 387 +#define _INTERNAL_INCREMENT_OPT_COUNTER 388 +#define _SHRINK_STACK 389 +#define MAX_UOP_ID 389 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 2b5b37e6b8d6a4..6aed6163ca19b9 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -16,38 +16,38 @@ 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, + [_NOP] = HAS_PURE_FLAG, [_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 | HAS_PURE_FLAG, - [_LOAD_FAST_AND_CLEAR] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, + [_LOAD_FAST_CHECK] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ERROR_FLAG | HAS_SPECIAL_OPT_FLAG, + [_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG | HAS_SPECIAL_OPT_FLAG, + [_LOAD_FAST_AND_CLEAR] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_SPECIAL_OPT_FLAG, [_LOAD_FAST_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, - [_LOAD_CONST] = HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_PURE_FLAG, - [_STORE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, + [_LOAD_CONST] = HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_PURE_FLAG | HAS_SPECIAL_OPT_FLAG, + [_STORE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_SPECIAL_OPT_FLAG, [_STORE_FAST_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, [_STORE_FAST_STORE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, [_POP_TOP] = HAS_PURE_FLAG, - [_PUSH_NULL] = HAS_PURE_FLAG, + [_PUSH_NULL] = HAS_PURE_FLAG | HAS_SPECIAL_OPT_FLAG, [_END_SEND] = HAS_PURE_FLAG, [_UNARY_NEGATIVE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_UNARY_NOT] = HAS_PURE_FLAG, [_TO_BOOL] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_TO_BOOL_BOOL] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_TO_BOOL_BOOL] = HAS_DEOPT_FLAG | HAS_GUARD_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 | HAS_PASSTHROUGH_FLAG, + [_GUARD_BOTH_INT] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, [_BINARY_OP_MULTIPLY_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, [_BINARY_OP_ADD_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, [_BINARY_OP_SUBTRACT_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, - [_GUARD_BOTH_FLOAT] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_GUARD_BOTH_FLOAT] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, [_BINARY_OP_MULTIPLY_FLOAT] = HAS_PURE_FLAG, [_BINARY_OP_ADD_FLOAT] = HAS_PURE_FLAG, [_BINARY_OP_SUBTRACT_FLOAT] = HAS_PURE_FLAG, - [_GUARD_BOTH_UNICODE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_GUARD_BOTH_UNICODE] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, [_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_PURE_FLAG, [_BINARY_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_BINARY_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -64,7 +64,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_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, + [_POP_FRAME] = HAS_ESCAPES_FLAG | HAS_SPECIAL_OPT_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, @@ -112,17 +112,17 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_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 | HAS_PASSTHROUGH_FLAG, - [_CHECK_MANAGED_OBJECT_HAS_VALUES] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_GUARD_TYPE_VERSION] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, + [_CHECK_MANAGED_OBJECT_HAS_VALUES] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, [_LOAD_ATTR_INSTANCE_VALUE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_CHECK_ATTR_MODULE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_CHECK_ATTR_MODULE] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, [_LOAD_ATTR_MODULE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_CHECK_ATTR_WITH_HINT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG | HAS_PASSTHROUGH_FLAG, + [_CHECK_ATTR_WITH_HINT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG | HAS_GUARD_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 | HAS_PASSTHROUGH_FLAG, + [_CHECK_ATTR_CLASS] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, [_LOAD_ATTR_CLASS] = HAS_ARG_FLAG, - [_GUARD_DORV_VALUES] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_GUARD_DORV_VALUES] = HAS_DEOPT_FLAG | HAS_GUARD_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, @@ -142,34 +142,34 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_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 | HAS_PASSTHROUGH_FLAG, - [_GUARD_NOT_EXHAUSTED_LIST] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_ITER_CHECK_LIST] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, + [_GUARD_NOT_EXHAUSTED_LIST] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, [_ITER_NEXT_LIST] = 0, - [_ITER_CHECK_TUPLE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, - [_GUARD_NOT_EXHAUSTED_TUPLE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_ITER_CHECK_TUPLE] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, + [_GUARD_NOT_EXHAUSTED_TUPLE] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, [_ITER_NEXT_TUPLE] = 0, - [_ITER_CHECK_RANGE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, - [_GUARD_NOT_EXHAUSTED_RANGE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_ITER_CHECK_RANGE] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, + [_GUARD_NOT_EXHAUSTED_RANGE] = HAS_DEOPT_FLAG | HAS_GUARD_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 | HAS_PASSTHROUGH_FLAG, - [_GUARD_KEYS_VERSION] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, + [_GUARD_KEYS_VERSION] = HAS_DEOPT_FLAG | HAS_GUARD_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 | HAS_PASSTHROUGH_FLAG, + [_CHECK_ATTR_METHOD_LAZY_DICT] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, [_LOAD_ATTR_METHOD_LAZY_DICT] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, - [_CHECK_CALL_BOUND_METHOD_EXACT_ARGS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_CHECK_CALL_BOUND_METHOD_EXACT_ARGS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_GUARD_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 | HAS_PASSTHROUGH_FLAG, - [_CHECK_STACK_SPACE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, - [_INIT_CALL_PY_EXACT_ARGS] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG | HAS_PURE_FLAG, - [_PUSH_FRAME] = HAS_ESCAPES_FLAG, + [_CHECK_PEP_523] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG | HAS_SPECIAL_OPT_FLAG, + [_CHECK_FUNCTION_EXACT_ARGS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_GUARD_FLAG, + [_CHECK_STACK_SPACE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_GUARD_FLAG, + [_INIT_CALL_PY_EXACT_ARGS] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG | HAS_PURE_FLAG | HAS_SPECIAL_OPT_FLAG, + [_PUSH_FRAME] = HAS_ESCAPES_FLAG | HAS_SPECIAL_OPT_FLAG, [_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, @@ -190,7 +190,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_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 | HAS_PURE_FLAG, + [_COPY] = HAS_ARG_FLAG | HAS_PURE_FLAG | HAS_SPECIAL_OPT_FLAG, [_BINARY_OP] = HAS_ARG_FLAG | HAS_ERROR_FLAG, [_SWAP] = HAS_ARG_FLAG | HAS_PURE_FLAG, [_GUARD_IS_TRUE_POP] = HAS_DEOPT_FLAG, @@ -198,17 +198,20 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_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, + [_SET_IP] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG | HAS_SPECIAL_OPT_FLAG, + [_SAVE_RETURN_OFFSET] = HAS_ARG_FLAG | HAS_SPECIAL_OPT_FLAG, [_EXIT_TRACE] = HAS_DEOPT_FLAG, - [_CHECK_VALIDITY] = HAS_DEOPT_FLAG, - [_LOAD_CONST_INLINE] = 0, - [_LOAD_CONST_INLINE_BORROW] = 0, - [_LOAD_CONST_INLINE_WITH_NULL] = 0, - [_LOAD_CONST_INLINE_BORROW_WITH_NULL] = 0, - [_CHECK_GLOBALS] = HAS_DEOPT_FLAG, - [_CHECK_BUILTINS] = HAS_DEOPT_FLAG, + [_JUMP_ABSOLUTE] = HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG, + [_JUMP_ABSOLUTE_HEADER] = 0, + [_CHECK_VALIDITY] = HAS_DEOPT_FLAG | HAS_SPECIAL_OPT_FLAG, + [_LOAD_CONST_INLINE] = HAS_PURE_FLAG | HAS_SPECIAL_OPT_FLAG, + [_LOAD_CONST_INLINE_BORROW] = HAS_PURE_FLAG | HAS_SPECIAL_OPT_FLAG, + [_LOAD_CONST_INLINE_WITH_NULL] = HAS_PURE_FLAG | HAS_SPECIAL_OPT_FLAG, + [_LOAD_CONST_INLINE_BORROW_WITH_NULL] = HAS_PURE_FLAG | HAS_SPECIAL_OPT_FLAG, + [_CHECK_GLOBALS] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG | HAS_SPECIAL_OPT_FLAG, + [_CHECK_BUILTINS] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG | HAS_SPECIAL_OPT_FLAG, [_INTERNAL_INCREMENT_OPT_COUNTER] = 0, + [_SHRINK_STACK] = HAS_ARG_FLAG, }; const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { @@ -319,6 +322,8 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_ITER_NEXT_LIST] = "_ITER_NEXT_LIST", [_ITER_NEXT_RANGE] = "_ITER_NEXT_RANGE", [_ITER_NEXT_TUPLE] = "_ITER_NEXT_TUPLE", + [_JUMP_ABSOLUTE] = "_JUMP_ABSOLUTE", + [_JUMP_ABSOLUTE_HEADER] = "_JUMP_ABSOLUTE_HEADER", [_JUMP_TO_TOP] = "_JUMP_TO_TOP", [_LIST_APPEND] = "_LIST_APPEND", [_LIST_EXTEND] = "_LIST_EXTEND", @@ -375,6 +380,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_SET_FUNCTION_ATTRIBUTE] = "_SET_FUNCTION_ATTRIBUTE", [_SET_IP] = "_SET_IP", [_SET_UPDATE] = "_SET_UPDATE", + [_SHRINK_STACK] = "_SHRINK_STACK", [_STORE_ATTR] = "_STORE_ATTR", [_STORE_ATTR_INSTANCE_VALUE] = "_STORE_ATTR_INSTANCE_VALUE", [_STORE_ATTR_SLOT] = "_STORE_ATTR_SLOT", @@ -408,6 +414,408 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { }; #endif // NEED_OPCODE_METADATA +extern int _PyUop_NetStackEffect(int opcode, int oparg); +#ifdef NEED_OPCODE_METADATA +int _PyUop_NetStackEffect(int opcode, int oparg) { + switch (opcode) { + case _NOP: + return (0); + case _RESUME_CHECK: + return (0); + case _LOAD_FAST_CHECK: + return (1); + case _LOAD_FAST: + return (1); + case _LOAD_FAST_AND_CLEAR: + return (1); + case _LOAD_FAST_LOAD_FAST: + return (2); + case _LOAD_CONST: + return (1); + case _STORE_FAST: + return (-1); + case _STORE_FAST_LOAD_FAST: + return (0); + case _STORE_FAST_STORE_FAST: + return (-2); + case _POP_TOP: + return (-1); + case _PUSH_NULL: + return (1); + case _END_SEND: + return (-1); + case _UNARY_NEGATIVE: + return (0); + case _UNARY_NOT: + return (0); + case _TO_BOOL: + return (0); + case _TO_BOOL_BOOL: + return (0); + case _TO_BOOL_INT: + return (0); + case _TO_BOOL_LIST: + return (0); + case _TO_BOOL_NONE: + return (0); + case _TO_BOOL_STR: + return (0); + case _TO_BOOL_ALWAYS_TRUE: + return (0); + case _UNARY_INVERT: + return (0); + case _GUARD_BOTH_INT: + return (0); + case _BINARY_OP_MULTIPLY_INT: + return (-1); + case _BINARY_OP_ADD_INT: + return (-1); + case _BINARY_OP_SUBTRACT_INT: + return (-1); + case _GUARD_BOTH_FLOAT: + return (0); + case _BINARY_OP_MULTIPLY_FLOAT: + return (-1); + case _BINARY_OP_ADD_FLOAT: + return (-1); + case _BINARY_OP_SUBTRACT_FLOAT: + return (-1); + case _GUARD_BOTH_UNICODE: + return (0); + case _BINARY_OP_ADD_UNICODE: + return (-1); + case _BINARY_SUBSCR: + return (-1); + case _BINARY_SLICE: + return (-2); + case _STORE_SLICE: + return (-4); + case _BINARY_SUBSCR_LIST_INT: + return (-1); + case _BINARY_SUBSCR_STR_INT: + return (-1); + case _BINARY_SUBSCR_TUPLE_INT: + return (-1); + case _BINARY_SUBSCR_DICT: + return (-1); + case _LIST_APPEND: + return (-1); + case _SET_ADD: + return (-1); + case _STORE_SUBSCR: + return (-3); + case _STORE_SUBSCR_LIST_INT: + return (-3); + case _STORE_SUBSCR_DICT: + return (-3); + case _DELETE_SUBSCR: + return (-2); + case _CALL_INTRINSIC_1: + return (0); + case _CALL_INTRINSIC_2: + return (-1); + case _POP_FRAME: + return (-1); + case _GET_AITER: + return (0); + case _GET_ANEXT: + return (1); + case _GET_AWAITABLE: + return (0); + case _POP_EXCEPT: + return (-1); + case _LOAD_ASSERTION_ERROR: + return (1); + case _LOAD_BUILD_CLASS: + return (1); + case _STORE_NAME: + return (-1); + case _DELETE_NAME: + return (0); + case _UNPACK_SEQUENCE: + return (-1 + oparg); + case _UNPACK_SEQUENCE_TWO_TUPLE: + return (-1 + oparg); + case _UNPACK_SEQUENCE_TUPLE: + return (-1 + oparg); + case _UNPACK_SEQUENCE_LIST: + return (-1 + oparg); + case _UNPACK_EX: + return ((oparg >> 8) + (oparg & 0xFF)); + case _STORE_ATTR: + return (-2); + case _DELETE_ATTR: + return (-1); + case _STORE_GLOBAL: + return (-1); + case _DELETE_GLOBAL: + return (0); + case _LOAD_LOCALS: + return (1); + case _LOAD_FROM_DICT_OR_GLOBALS: + return (0); + case _LOAD_NAME: + return (1); + case _LOAD_GLOBAL: + return (1 + (oparg & 1)); + case _GUARD_GLOBALS_VERSION: + return (0); + case _GUARD_BUILTINS_VERSION: + return (0); + case _LOAD_GLOBAL_MODULE: + return (1 + (oparg & 1)); + case _LOAD_GLOBAL_BUILTINS: + return (1 + (oparg & 1)); + case _DELETE_FAST: + return (0); + case _MAKE_CELL: + return (0); + case _DELETE_DEREF: + return (0); + case _LOAD_FROM_DICT_OR_DEREF: + return (0); + case _LOAD_DEREF: + return (1); + case _STORE_DEREF: + return (-1); + case _COPY_FREE_VARS: + return (0); + case _BUILD_STRING: + return (1 - oparg); + case _BUILD_TUPLE: + return (1 - oparg); + case _BUILD_LIST: + return (1 - oparg); + case _LIST_EXTEND: + return (-1); + case _SET_UPDATE: + return (-1); + case _BUILD_SET: + return (1 - oparg); + case _BUILD_MAP: + return (1 - oparg*2); + case _SETUP_ANNOTATIONS: + return (0); + case _BUILD_CONST_KEY_MAP: + return (-oparg); + case _DICT_UPDATE: + return (-1); + case _DICT_MERGE: + return (-1); + case _MAP_ADD: + return (-2); + case _LOAD_SUPER_ATTR_ATTR: + return (-2 + ((0) ? 1 : 0)); + case _LOAD_SUPER_ATTR_METHOD: + return (-1); + case _LOAD_ATTR: + return ((oparg & 1)); + case _GUARD_TYPE_VERSION: + return (0); + case _CHECK_MANAGED_OBJECT_HAS_VALUES: + return (0); + case _LOAD_ATTR_INSTANCE_VALUE: + return ((oparg & 1)); + case _CHECK_ATTR_MODULE: + return (0); + case _LOAD_ATTR_MODULE: + return ((oparg & 1)); + case _CHECK_ATTR_WITH_HINT: + return (0); + case _LOAD_ATTR_WITH_HINT: + return ((oparg & 1)); + case _LOAD_ATTR_SLOT: + return ((oparg & 1)); + case _CHECK_ATTR_CLASS: + return (0); + case _LOAD_ATTR_CLASS: + return ((oparg & 1)); + case _GUARD_DORV_VALUES: + return (0); + case _STORE_ATTR_INSTANCE_VALUE: + return (-2); + case _STORE_ATTR_SLOT: + return (-2); + case _COMPARE_OP: + return (-1); + case _COMPARE_OP_FLOAT: + return (-1); + case _COMPARE_OP_INT: + return (-1); + case _COMPARE_OP_STR: + return (-1); + case _IS_OP: + return (-1); + case _CONTAINS_OP: + return (-1); + case _CHECK_EG_MATCH: + return (0); + case _CHECK_EXC_MATCH: + return (0); + case _IS_NONE: + return (0); + case _GET_LEN: + return (1); + case _MATCH_CLASS: + return (-2); + case _MATCH_MAPPING: + return (1); + case _MATCH_SEQUENCE: + return (1); + case _MATCH_KEYS: + return (1); + case _GET_ITER: + return (0); + case _GET_YIELD_FROM_ITER: + return (0); + case _FOR_ITER_TIER_TWO: + return (1); + case _ITER_CHECK_LIST: + return (0); + case _GUARD_NOT_EXHAUSTED_LIST: + return (0); + case _ITER_NEXT_LIST: + return (1); + case _ITER_CHECK_TUPLE: + return (0); + case _GUARD_NOT_EXHAUSTED_TUPLE: + return (0); + case _ITER_NEXT_TUPLE: + return (1); + case _ITER_CHECK_RANGE: + return (0); + case _GUARD_NOT_EXHAUSTED_RANGE: + return (0); + case _ITER_NEXT_RANGE: + return (1); + case _BEFORE_ASYNC_WITH: + return (1); + case _BEFORE_WITH: + return (1); + case _WITH_EXCEPT_START: + return (1); + case _PUSH_EXC_INFO: + return (1); + case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT: + return (0); + case _GUARD_KEYS_VERSION: + return (0); + case _LOAD_ATTR_METHOD_WITH_VALUES: + return (((1) ? 1 : 0)); + case _LOAD_ATTR_METHOD_NO_DICT: + return (((1) ? 1 : 0)); + case _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: + return (((0) ? 1 : 0)); + case _LOAD_ATTR_NONDESCRIPTOR_NO_DICT: + return (((0) ? 1 : 0)); + case _CHECK_ATTR_METHOD_LAZY_DICT: + return (0); + case _LOAD_ATTR_METHOD_LAZY_DICT: + return (((1) ? 1 : 0)); + case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: + return (0); + case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: + return (0); + case _CHECK_PEP_523: + return (0); + case _CHECK_FUNCTION_EXACT_ARGS: + return (0); + case _CHECK_STACK_SPACE: + return (0); + case _INIT_CALL_PY_EXACT_ARGS: + return (-1 - oparg); + case _PUSH_FRAME: + return (-1 + ((0) ? 1 : 0)); + case _CALL_TYPE_1: + return (-1 - oparg); + case _CALL_STR_1: + return (-1 - oparg); + case _CALL_TUPLE_1: + return (-1 - oparg); + case _EXIT_INIT_CHECK: + return (-1); + case _CALL_BUILTIN_CLASS: + return (-1 - oparg); + case _CALL_BUILTIN_O: + return (-1 - oparg); + case _CALL_BUILTIN_FAST: + return (-1 - oparg); + case _CALL_BUILTIN_FAST_WITH_KEYWORDS: + return (-1 - oparg); + case _CALL_LEN: + return (-1 - oparg); + case _CALL_ISINSTANCE: + return (-1 - oparg); + case _CALL_METHOD_DESCRIPTOR_O: + return (-1 - oparg); + case _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: + return (-1 - oparg); + case _CALL_METHOD_DESCRIPTOR_NOARGS: + return (-1 - oparg); + case _CALL_METHOD_DESCRIPTOR_FAST: + return (-1 - oparg); + case _MAKE_FUNCTION: + return (0); + case _SET_FUNCTION_ATTRIBUTE: + return (-1); + case _BUILD_SLICE: + return (-1 - ((oparg == 3) ? 1 : 0)); + case _CONVERT_VALUE: + return (0); + case _FORMAT_SIMPLE: + return (0); + case _FORMAT_WITH_SPEC: + return (-1); + case _COPY: + return (1); + case _BINARY_OP: + return (-1); + case _SWAP: + return (0); + case _GUARD_IS_TRUE_POP: + return (-1); + case _GUARD_IS_FALSE_POP: + return (-1); + case _GUARD_IS_NONE_POP: + return (-1); + case _GUARD_IS_NOT_NONE_POP: + return (-1); + case _JUMP_TO_TOP: + return (0); + case _SET_IP: + return (0); + case _SAVE_RETURN_OFFSET: + return (0); + case _EXIT_TRACE: + return (0); + case _JUMP_ABSOLUTE: + return (0); + case _JUMP_ABSOLUTE_HEADER: + return (0); + case _CHECK_VALIDITY: + return (0); + case _LOAD_CONST_INLINE: + return (1); + case _LOAD_CONST_INLINE_BORROW: + return (1); + case _LOAD_CONST_INLINE_WITH_NULL: + return (2); + case _LOAD_CONST_INLINE_BORROW_WITH_NULL: + return (2); + case _CHECK_GLOBALS: + return (0); + case _CHECK_BUILTINS: + return (0); + case _INTERNAL_INCREMENT_OPT_COUNTER: + return (-1); + case _SHRINK_STACK: + return (-oparg); + default: Py_UNREACHABLE(); + }; +}; + +#endif // NEED_OPCODE_METADATA + #ifdef __cplusplus } diff --git a/Lib/test/test_capi/test_mem.py b/Lib/test/test_capi/test_mem.py index 04f17a9ec9e72a..0aad2cc46d5afa 100644 --- a/Lib/test/test_capi/test_mem.py +++ b/Lib/test/test_capi/test_mem.py @@ -118,6 +118,9 @@ def test_pyobject_freed_is_freed(self): def test_set_nomemory(self): code = """if 1: import _testcapi + import _testinternalcapi + old_opt = _testinternalcapi.get_optimizer() + _testinternalcapi.set_optimizer(None) class C(): pass @@ -141,6 +144,8 @@ class C(): pass print('MemoryError', outer_cnt, j) _testcapi.remove_mem_hooks() break + + _testinternalcapi.set_optimizer(old_opt) """ rc, out, err = assert_python_ok('-c', code) lines = out.splitlines() diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 5c8c0596610303..3b0c2532d72528 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2,9 +2,12 @@ import opcode import textwrap import unittest +import gc import _testinternalcapi +from test.support.script_helper import assert_python_ok +from test import support @contextlib.contextmanager def temporary_optimizer(opt): @@ -342,7 +345,7 @@ def testfunc(n): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) uops = {opname for opname, _, _ in ex} - self.assertIn("_JUMP_TO_TOP", uops) + self.assertIn("_JUMP_ABSOLUTE", uops) def test_jump_forward(self): def testfunc(n): @@ -540,6 +543,396 @@ def testfunc(n): # too much already. self.assertEqual(count, 1) +class TestUopsOptimization(unittest.TestCase): + + def test_int_constant_propagation(self): + def testfunc(loops): + num = 0 + for _ in range(loops): + x = 0 + y = 1 + a = x + y + return 1 + + opt = _testinternalcapi.get_uop_optimizer() + res = None + with temporary_optimizer(opt): + res = testfunc(64) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + self.assertEqual(res, 1) + binop_count = [opname for opname, _, _ in ex if opname == "_BINARY_OP_ADD_INT"] + self.assertEqual(len(binop_count), 0) + uops = {opname for opname, _, _ in ex} + self.assertNotIn("_SHRINK_STACK", uops) + + def test_int_constant_propagation_many(self): + def testfunc(loops): + num = 0 + for _ in range(loops): + x = 0 + y = 1 + a = x + y + x + y + x + y + x + y + return a + + opt = _testinternalcapi.get_uop_optimizer() + res = None + with temporary_optimizer(opt): + res = testfunc(64) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + self.assertEqual(res, 4) + binop_count = [opname for opname, _, _ in ex if opname == "_BINARY_OP_ADD_INT"] + self.assertEqual(len(binop_count), 0) + uops = {opname for opname, _, _ in ex} + self.assertNotIn("_SHRINK_STACK", uops) + + def test_int_type_propagation(self): + def testfunc(loops): + num = 0 + while num < loops: + x = num + num + a = x + 1 + num += 1 + return a + + opt = _testinternalcapi.get_uop_optimizer() + res = None + with temporary_optimizer(opt): + res = testfunc(32) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + self.assertEqual(res, 63) + binop_count = [opname for opname, _, _ in ex if opname == "_BINARY_OP_ADD_INT"] + guard_both_int_count = [opname for opname, _, _ in ex if opname == "_GUARD_BOTH_INT"] + self.assertGreaterEqual(len(binop_count), 3) + self.assertLessEqual(len(guard_both_int_count), 1) + + def test_int_impure_region(self): + def testfunc(loops): + num = 0 + while num < loops: + x = num + num + y = 1 + x // 2 + a = x + y + num += 1 + return a + + opt = _testinternalcapi.get_uop_optimizer() + res = None + with temporary_optimizer(opt): + res = testfunc(64) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + binop_count = [opname for opname, _, _ in ex if opname == "_BINARY_OP_ADD_INT"] + self.assertGreaterEqual(len(binop_count), 3) + + def test_int_impure_region_attr(self): + class A: + foo = 1 + def testfunc(loops): + num = 0 + while num < loops: + x = A.foo + A.foo + y = 1 + A.foo + a = x + y + num += 1 + return a + + opt = _testinternalcapi.get_uop_optimizer() + res = None + with temporary_optimizer(opt): + res = testfunc(64) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + binop_count = [opname for opname, _, _ in ex if opname == "_BINARY_OP_ADD_INT"] + self.assertGreaterEqual(len(binop_count), 3) + + def test_call_constant_propagate_past_impure(self): + def testfunc(n): + for i in range(n): + x = 1 + y = 1 + x // y + z = x + y + return z + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + res = testfunc(20) + + ex = get_first_executor(testfunc) + self.assertEqual(res, 2) + self.assertIsNotNone(ex) + uops = {opname for opname, _, _ in ex} + self.assertNotIn("_BINARY_OP_ADD_INT", uops) + + def test_int_large_pure_region(self): + def testfunc(loops): + num = 0 + while num < loops: + x = num + num + num - num + num - num + num + num + num - num + num - num + y = 1 + a = x + num + num + num + num += 1 + return a + + opt = _testinternalcapi.get_uop_optimizer() + res = None + with temporary_optimizer(opt): + res = testfunc(64) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + binop_count = [opname for opname, _, _ in ex if opname == "_BINARY_OP_ADD_INT"] + self.assertGreaterEqual(len(binop_count), 11) + + def test_call_py_exact_args(self): + def testfunc(n): + def dummy(x): + return x+1 + for i in range(n): + dummy(i) + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + testfunc(20) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + uops = {opname for opname, _, _ in ex} + self.assertIn("_PUSH_FRAME", uops) + self.assertIn("_BINARY_OP_ADD_INT", uops) + self.assertNotIn("_CHECK_PEP_523", uops) + + def test_frame_instance_method(self): + class A: + def __init__(self): + self.a = 1 + def foo(self): + return self.a + + a = A() + def testfunc(n): + for i in range(n): + a.foo() + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + testfunc(32) + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + uops = {opname for opname, _, _ in ex} + self.assertIn("_LOAD_ATTR_METHOD_WITH_VALUES", uops) + + def test_frame_class_method(self): + class A: + def __init__(self): + self.a = 1 + def foo(self): + return self.a + + def testfunc(n): + a = A() + for i in range(n): + A.foo(a) + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + testfunc(32) + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + uops = {opname for opname, _, _ in ex} + self.assertIn("_LOAD_ATTR_CLASS", uops) + + def test_call_constant_propagate_in_frame(self): + def testfunc(n): + def dummy(): + x = 1 + y = 1 + return x+y + for i in range(n): + x = dummy() + return x + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + res = testfunc(20) + + ex = get_first_executor(testfunc) + self.assertEqual(res, 2) + self.assertIsNotNone(ex) + uops = {opname for opname, _, _ in ex} + self.assertIn("_PUSH_FRAME", uops) + self.assertNotIn("_BINARY_OP_ADD_INT", uops) + + def test_call_constant_propagate_through_frame(self): + def testfunc(n): + def dummy(x): + return x+1 + for i in range(n): + x = dummy(3) + return x + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + res = testfunc(20) + + ex = get_first_executor(testfunc) + self.assertEqual(res, 4) + self.assertIsNotNone(ex) + uops = {opname for opname, _, _ in ex} + self.assertIn("_PUSH_FRAME", uops) + self.assertNotIn("_BINARY_OP_ADD_INT", uops) + + def test_int_type_propagate_through_range(self): + def testfunc(n): + + for i in range(n): + x = i + i + return x + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + res = testfunc(20) + + ex = get_first_executor(testfunc) + self.assertEqual(res, 19 * 2) + self.assertIsNotNone(ex) + uops = {opname for opname, _, _ in ex} + self.assertNotIn("_GUARD_BOTH_INT", uops) + + def test_int_value_nubmering(self): + def testfunc(n): + + y = 1 + for i in range(n): + x = y + z = x + a = z + b = a + res = x + z + a + b + return res + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + res = testfunc(20) + + ex = get_first_executor(testfunc) + self.assertEqual(res, 4) + self.assertIsNotNone(ex) + uops = {opname for opname, _, _ in ex} + self.assertIn("_GUARD_BOTH_INT", uops) + guard_count = [opname for opname, _, _ in ex if opname == "_GUARD_BOTH_INT"] + self.assertEqual(len(guard_count), 1) + + def test_comprehension(self): + def testfunc(n): + for _ in range(n): + return [i for i in range(n)] + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + testfunc(20) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + uops = {opname for opname, _, _ in ex} + self.assertNotIn("_BINARY_OP_ADD_INT", uops) + + def test_loop_peeling(self): + def testfunc(loops): + num = 0 + for _ in range(loops): + x = 0 + y = 1 + a = x + y + return 1 + + opt = _testinternalcapi.get_uop_optimizer() + res = None + with temporary_optimizer(opt): + res = testfunc(64) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + self.assertEqual(res, 1) + binop_count = [opname for opname, _, _ in ex if opname == "_BINARY_OP_ADD_INT"] + self.assertEqual(len(binop_count), 0) + uops = {opname for opname, _, _ in ex} + self.assertNotIn("_SHRINK_STACK", uops) + iter_next_count = [opname for opname, _, _ in ex if opname == "_ITER_NEXT_RANGE"] + self.assertLessEqual(len(iter_next_count), 2) + + def test_call_py_exact_args_disappearing(self): + def dummy(x): + return x+1 + + def testfunc(n): + for i in range(n): + dummy(i) + + opt = _testinternalcapi.get_uop_optimizer() + # Trigger specialization + testfunc(8) + with temporary_optimizer(opt): + del dummy + gc.collect() + + def dummy(x): + return x + 2 + testfunc(10) + + ex = get_first_executor(testfunc) + # Honestly as long as it doesn't crash it's fine. + # Whether we get an executor or not is non-deterministic, + # because it's decided by when the function is freed. + # This test is a little implementation specific. + + def test_promote_globals_to_constants(self): + def testfunc(n): + for i in range(n): + x = range(i) + return x + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + testfunc(20) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + uops = {opname for opname, _, _ in ex} + self.assertNotIn("_LOAD_GLOBAL_BUILTIN", uops) + self.assertIn("_LOAD_CONST_INLINE_BORROW_WITH_NULL", uops) + + def test_promote_globals_to_constants_propagate(self): + def testfunc(n): + for i in range(n): + x = Foo.attr + return x + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + res = testfunc(20) + + self.assertEqual(res, Foo.attr) + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + uops = {opname for opname, _, _ in ex} + self.assertNotIn("_CHECK_ATTR_CLASS", uops) + self.assertIn("_LOAD_ATTR_CLASS", uops) + + +class Foo: + attr = 1 + if __name__ == "__main__": unittest.main() diff --git a/Makefile.pre.in b/Makefile.pre.in index aad637876ead80..6b3c5026eff25c 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1605,6 +1605,8 @@ regen-cases: -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/tier2_abstract_generator.py \ + -o $(srcdir)/Python/abstract_interp_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 \ @@ -1616,6 +1618,7 @@ regen-cases: $(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 Python/compile.o: $(srcdir)/Include/internal/pycore_opcode_metadata.h @@ -1637,7 +1640,8 @@ Python/optimizer.o: \ Python/optimizer_analysis.o: \ $(srcdir)/Include/internal/pycore_opcode_metadata.h \ - $(srcdir)/Include/internal/pycore_optimizer.h + $(srcdir)/Include/internal/pycore_optimizer.h \ + $(srcdir)/Python/abstract_interp_cases.c.h Python/frozen.o: $(FROZEN_FILES_OUT) diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-01-16-14-41-54.gh-issue-114058.Cb2b8h.rst b/Misc/NEWS.d/next/Core and Builtins/2024-01-16-14-41-54.gh-issue-114058.Cb2b8h.rst new file mode 100644 index 00000000000000..32d98c1a1a8d0a --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-01-16-14-41-54.gh-issue-114058.Cb2b8h.rst @@ -0,0 +1 @@ +Enable the tier 2 optimizer for all uops. diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h new file mode 100644 index 00000000000000..bfedfb6da60581 --- /dev/null +++ b/Python/abstract_interp_cases.c.h @@ -0,0 +1,1997 @@ +// This file is generated by Tools/cases_generator/tier2_abstract_generator.py +// from: +// Python/bytecodes.c +// Do not edit! + +#ifdef TIER_ONE + #error "This file is for Tier 2 only" +#endif +#define TIER_TWO 2 + + case _NOP: { + break; + } + + case _RESUME_CHECK: { + break; + } + + /* _INSTRUMENTED_RESUME is not a viable micro-op for tier 2 */ + + case _POP_TOP: { + _Py_UOpsSymType *__value_; + __value_ = stack_pointer[-1]; + (void)__value_; + stack_pointer += -1; + break; + } + + case _END_SEND: { + _Py_UOpsSymType *__value_; + _Py_UOpsSymType *__receiver_; + __value_ = stack_pointer[-1]; + __receiver_ = stack_pointer[-2]; + (void)__receiver_; + (void)__value_; + stack_pointer[-2] = __value_; + stack_pointer += -1; + break; + } + + case _UNARY_NEGATIVE: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-1] = __res_; + break; + } + + case _UNARY_NOT: { + _Py_UOpsSymType *__value_; + _Py_UOpsSymType *__res_; + __value_ = stack_pointer[-1]; + // Constant evaluation + if (is_const(__value_)) { + PyObject *value; + PyObject *res; + value = get_const(__value_); + assert(PyBool_Check(value)); + res = Py_IsFalse(value) ? Py_True : Py_False; + __res_ = _Py_UOpsSymType_New(ctx, (PyObject *)res); + if(__res_ == NULL) { goto error; } + if (emit_const(&ctx->emitter, (PyObject *)res, 1) < 0) { goto error; } + new_inst.opcode = _NOP; + } + else { + __res_ = _Py_UOpsSymType_New(ctx, NULL); + if (__res_ == NULL) { goto error; } + } + if (__res_ == NULL) goto error; + stack_pointer[-1] = __res_; + break; + } + + case _TO_BOOL: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-1] = __res_; + break; + } + + case _TO_BOOL_BOOL: { + _Py_UOpsSymType *__value_; + __value_ = stack_pointer[-1]; + // Constant evaluation + if (is_const(__value_)) { + PyObject *value; + value = get_const(__value_); + if (!PyBool_Check(value)) goto error; + STAT_INC(TO_BOOL, hit); + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + break; + } + + case _TO_BOOL_INT: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-1] = __res_; + break; + } + + case _TO_BOOL_LIST: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-1] = __res_; + break; + } + + case _TO_BOOL_NONE: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-1] = __res_; + break; + } + + case _TO_BOOL_STR: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-1] = __res_; + break; + } + + case _TO_BOOL_ALWAYS_TRUE: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-1] = __res_; + break; + } + + case _UNARY_INVERT: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-1] = __res_; + break; + } + + case _GUARD_BOTH_INT: { + _Py_UOpsSymType *__right_; + _Py_UOpsSymType *__left_; + __right_ = stack_pointer[-1]; + __left_ = stack_pointer[-2]; + // Constant evaluation + if (is_const(__left_) && is_const(__right_)) { + PyObject *right; + PyObject *left; + left = get_const(__left_); + right = get_const(__right_); + if (!PyLong_CheckExact(left)) goto error; + if (!PyLong_CheckExact(right)) goto error; + + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + // Type guard elimination + if (sym_matches_type((_Py_UOpsSymType *)__left_, PYLONG_TYPE, (uint32_t)0) && sym_matches_type((_Py_UOpsSymType *)__right_, PYLONG_TYPE, (uint32_t)0)) { + DPRINTF(2, "type propagation eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + else { + // Type propagation + sym_set_type((_Py_UOpsSymType *)__left_, PYLONG_TYPE, (uint32_t)0); + sym_set_type((_Py_UOpsSymType *)__right_, PYLONG_TYPE, (uint32_t)0); + } + break; + } + + case _BINARY_OP_MULTIPLY_INT: { + _Py_UOpsSymType *__right_; + _Py_UOpsSymType *__left_; + _Py_UOpsSymType *__res_; + __right_ = stack_pointer[-1]; + __left_ = stack_pointer[-2]; + // Constant evaluation + if (is_const(__left_) && is_const(__right_)) { + PyObject *right; + PyObject *left; + PyObject *res; + left = get_const(__left_); + right = get_const(__right_); + STAT_INC(BINARY_OP, hit); + res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); + _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); + _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); + if (res == NULL) goto pop_2_error_tier_two; + + __res_ = _Py_UOpsSymType_New(ctx, (PyObject *)res); + if(__res_ == NULL) { goto error; } + if (emit_const(&ctx->emitter, (PyObject *)res, 2) < 0) { goto error; } + new_inst.opcode = _NOP; + } + else { + __res_ = _Py_UOpsSymType_New(ctx, NULL); + if (__res_ == NULL) { goto error; } + } + if (__res_ == NULL) goto error; + // Type propagation + sym_set_type(__res_, PYLONG_TYPE, (uint32_t)0); + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + case _BINARY_OP_ADD_INT: { + _Py_UOpsSymType *__right_; + _Py_UOpsSymType *__left_; + _Py_UOpsSymType *__res_; + __right_ = stack_pointer[-1]; + __left_ = stack_pointer[-2]; + // Constant evaluation + if (is_const(__left_) && is_const(__right_)) { + PyObject *right; + PyObject *left; + PyObject *res; + left = get_const(__left_); + right = get_const(__right_); + STAT_INC(BINARY_OP, hit); + res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); + _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); + _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); + if (res == NULL) goto pop_2_error_tier_two; + + __res_ = _Py_UOpsSymType_New(ctx, (PyObject *)res); + if(__res_ == NULL) { goto error; } + if (emit_const(&ctx->emitter, (PyObject *)res, 2) < 0) { goto error; } + new_inst.opcode = _NOP; + } + else { + __res_ = _Py_UOpsSymType_New(ctx, NULL); + if (__res_ == NULL) { goto error; } + } + if (__res_ == NULL) goto error; + // Type propagation + sym_set_type(__res_, PYLONG_TYPE, (uint32_t)0); + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + case _BINARY_OP_SUBTRACT_INT: { + _Py_UOpsSymType *__right_; + _Py_UOpsSymType *__left_; + _Py_UOpsSymType *__res_; + __right_ = stack_pointer[-1]; + __left_ = stack_pointer[-2]; + // Constant evaluation + if (is_const(__left_) && is_const(__right_)) { + PyObject *right; + PyObject *left; + PyObject *res; + left = get_const(__left_); + right = get_const(__right_); + STAT_INC(BINARY_OP, hit); + res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); + _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); + _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); + if (res == NULL) goto pop_2_error_tier_two; + + __res_ = _Py_UOpsSymType_New(ctx, (PyObject *)res); + if(__res_ == NULL) { goto error; } + if (emit_const(&ctx->emitter, (PyObject *)res, 2) < 0) { goto error; } + new_inst.opcode = _NOP; + } + else { + __res_ = _Py_UOpsSymType_New(ctx, NULL); + if (__res_ == NULL) { goto error; } + } + if (__res_ == NULL) goto error; + // Type propagation + sym_set_type(__res_, PYLONG_TYPE, (uint32_t)0); + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + case _GUARD_BOTH_FLOAT: { + _Py_UOpsSymType *__right_; + _Py_UOpsSymType *__left_; + __right_ = stack_pointer[-1]; + __left_ = stack_pointer[-2]; + // Constant evaluation + if (is_const(__left_) && is_const(__right_)) { + PyObject *right; + PyObject *left; + left = get_const(__left_); + right = get_const(__right_); + if (!PyFloat_CheckExact(left)) goto error; + if (!PyFloat_CheckExact(right)) goto error; + + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + // Type guard elimination + if (sym_matches_type((_Py_UOpsSymType *)__left_, PYFLOAT_TYPE, (uint32_t)0) && sym_matches_type((_Py_UOpsSymType *)__right_, PYFLOAT_TYPE, (uint32_t)0)) { + DPRINTF(2, "type propagation eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + else { + // Type propagation + sym_set_type((_Py_UOpsSymType *)__left_, PYFLOAT_TYPE, (uint32_t)0); + sym_set_type((_Py_UOpsSymType *)__right_, PYFLOAT_TYPE, (uint32_t)0); + } + break; + } + + case _BINARY_OP_MULTIPLY_FLOAT: { + _Py_UOpsSymType *__right_; + _Py_UOpsSymType *__left_; + _Py_UOpsSymType *__res_; + __right_ = stack_pointer[-1]; + __left_ = stack_pointer[-2]; + // Constant evaluation + if (is_const(__left_) && is_const(__right_)) { + PyObject *right; + PyObject *left; + PyObject *res; + left = get_const(__left_); + right = get_const(__right_); + STAT_INC(BINARY_OP, hit); + double dres = + ((PyFloatObject *)left)->ob_fval * + ((PyFloatObject *)right)->ob_fval; + DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); + __res_ = _Py_UOpsSymType_New(ctx, (PyObject *)res); + if(__res_ == NULL) { goto error; } + if (emit_const(&ctx->emitter, (PyObject *)res, 2) < 0) { goto error; } + new_inst.opcode = _NOP; + } + else { + __res_ = _Py_UOpsSymType_New(ctx, NULL); + if (__res_ == NULL) { goto error; } + } + if (__res_ == NULL) goto error; + // Type propagation + sym_set_type(__res_, PYFLOAT_TYPE, (uint32_t)0); + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + case _BINARY_OP_ADD_FLOAT: { + _Py_UOpsSymType *__right_; + _Py_UOpsSymType *__left_; + _Py_UOpsSymType *__res_; + __right_ = stack_pointer[-1]; + __left_ = stack_pointer[-2]; + // Constant evaluation + if (is_const(__left_) && is_const(__right_)) { + PyObject *right; + PyObject *left; + PyObject *res; + left = get_const(__left_); + right = get_const(__right_); + STAT_INC(BINARY_OP, hit); + double dres = + ((PyFloatObject *)left)->ob_fval + + ((PyFloatObject *)right)->ob_fval; + DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); + __res_ = _Py_UOpsSymType_New(ctx, (PyObject *)res); + if(__res_ == NULL) { goto error; } + if (emit_const(&ctx->emitter, (PyObject *)res, 2) < 0) { goto error; } + new_inst.opcode = _NOP; + } + else { + __res_ = _Py_UOpsSymType_New(ctx, NULL); + if (__res_ == NULL) { goto error; } + } + if (__res_ == NULL) goto error; + // Type propagation + sym_set_type(__res_, PYFLOAT_TYPE, (uint32_t)0); + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + case _BINARY_OP_SUBTRACT_FLOAT: { + _Py_UOpsSymType *__right_; + _Py_UOpsSymType *__left_; + _Py_UOpsSymType *__res_; + __right_ = stack_pointer[-1]; + __left_ = stack_pointer[-2]; + // Constant evaluation + if (is_const(__left_) && is_const(__right_)) { + PyObject *right; + PyObject *left; + PyObject *res; + left = get_const(__left_); + right = get_const(__right_); + STAT_INC(BINARY_OP, hit); + double dres = + ((PyFloatObject *)left)->ob_fval - + ((PyFloatObject *)right)->ob_fval; + DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); + __res_ = _Py_UOpsSymType_New(ctx, (PyObject *)res); + if(__res_ == NULL) { goto error; } + if (emit_const(&ctx->emitter, (PyObject *)res, 2) < 0) { goto error; } + new_inst.opcode = _NOP; + } + else { + __res_ = _Py_UOpsSymType_New(ctx, NULL); + if (__res_ == NULL) { goto error; } + } + if (__res_ == NULL) goto error; + // Type propagation + sym_set_type(__res_, PYFLOAT_TYPE, (uint32_t)0); + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + case _GUARD_BOTH_UNICODE: { + _Py_UOpsSymType *__right_; + _Py_UOpsSymType *__left_; + __right_ = stack_pointer[-1]; + __left_ = stack_pointer[-2]; + // Constant evaluation + if (is_const(__left_) && is_const(__right_)) { + PyObject *right; + PyObject *left; + left = get_const(__left_); + right = get_const(__right_); + if (!PyUnicode_CheckExact(left)) goto error; + if (!PyUnicode_CheckExact(right)) goto error; + + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + // Type guard elimination + if (sym_matches_type((_Py_UOpsSymType *)__left_, PYUNICODE_TYPE, (uint32_t)0) && sym_matches_type((_Py_UOpsSymType *)__right_, PYUNICODE_TYPE, (uint32_t)0)) { + DPRINTF(2, "type propagation eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + else { + // Type propagation + sym_set_type((_Py_UOpsSymType *)__left_, PYUNICODE_TYPE, (uint32_t)0); + sym_set_type((_Py_UOpsSymType *)__right_, PYUNICODE_TYPE, (uint32_t)0); + } + break; + } + + case _BINARY_OP_ADD_UNICODE: { + _Py_UOpsSymType *__right_; + _Py_UOpsSymType *__left_; + _Py_UOpsSymType *__res_; + __right_ = stack_pointer[-1]; + __left_ = stack_pointer[-2]; + // Constant evaluation + if (is_const(__left_) && is_const(__right_)) { + PyObject *right; + PyObject *left; + PyObject *res; + left = get_const(__left_); + right = get_const(__right_); + STAT_INC(BINARY_OP, hit); + res = PyUnicode_Concat(left, right); + _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); + _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); + if (res == NULL) goto pop_2_error_tier_two; + + __res_ = _Py_UOpsSymType_New(ctx, (PyObject *)res); + if(__res_ == NULL) { goto error; } + if (emit_const(&ctx->emitter, (PyObject *)res, 2) < 0) { goto error; } + new_inst.opcode = _NOP; + } + else { + __res_ = _Py_UOpsSymType_New(ctx, NULL); + if (__res_ == NULL) { goto error; } + } + if (__res_ == NULL) goto error; + // Type propagation + sym_set_type(__res_, PYUNICODE_TYPE, (uint32_t)0); + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + case _BINARY_SUBSCR: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + case _BINARY_SLICE: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-3] = __res_; + stack_pointer += -2; + break; + } + + case _STORE_SLICE: { + stack_pointer += -4; + break; + } + + case _BINARY_SUBSCR_LIST_INT: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + case _BINARY_SUBSCR_STR_INT: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + case _BINARY_SUBSCR_TUPLE_INT: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + case _BINARY_SUBSCR_DICT: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + /* _BINARY_SUBSCR_GETITEM is not a viable micro-op for tier 2 */ + + case _LIST_APPEND: { + stack_pointer += -1; + break; + } + + case _SET_ADD: { + stack_pointer += -1; + break; + } + + case _STORE_SUBSCR: { + stack_pointer += -3; + break; + } + + case _STORE_SUBSCR_LIST_INT: { + stack_pointer += -3; + break; + } + + case _STORE_SUBSCR_DICT: { + stack_pointer += -3; + break; + } + + case _DELETE_SUBSCR: { + stack_pointer += -2; + break; + } + + case _CALL_INTRINSIC_1: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-1] = __res_; + break; + } + + case _CALL_INTRINSIC_2: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + /* _INSTRUMENTED_RETURN_VALUE is not a viable micro-op for tier 2 */ + + /* _INSTRUMENTED_RETURN_CONST is not a viable micro-op for tier 2 */ + + case _GET_AITER: { + _Py_UOpsSymType *__iter_; + __iter_ = sym_init_unknown(ctx); + if(__iter_ == NULL) goto error; + stack_pointer[-1] = __iter_; + break; + } + + case _GET_ANEXT: { + _Py_UOpsSymType *__awaitable_; + __awaitable_ = sym_init_unknown(ctx); + if(__awaitable_ == NULL) goto error; + stack_pointer[0] = __awaitable_; + stack_pointer += 1; + break; + } + + case _GET_AWAITABLE: { + _Py_UOpsSymType *__iter_; + __iter_ = sym_init_unknown(ctx); + if(__iter_ == NULL) goto error; + stack_pointer[-1] = __iter_; + break; + } + + /* _SEND is not a viable micro-op for tier 2 */ + + /* _SEND_GEN is not a viable micro-op for tier 2 */ + + /* _INSTRUMENTED_YIELD_VALUE is not a viable micro-op for tier 2 */ + + case _POP_EXCEPT: { + stack_pointer += -1; + break; + } + + case _LOAD_ASSERTION_ERROR: { + _Py_UOpsSymType *__value_; + __value_ = sym_init_unknown(ctx); + if(__value_ == NULL) goto error; + stack_pointer[0] = __value_; + stack_pointer += 1; + break; + } + + case _LOAD_BUILD_CLASS: { + _Py_UOpsSymType *__bc_; + __bc_ = sym_init_unknown(ctx); + if(__bc_ == NULL) goto error; + stack_pointer[0] = __bc_; + stack_pointer += 1; + break; + } + + case _STORE_NAME: { + stack_pointer += -1; + break; + } + + case _DELETE_NAME: { + break; + } + + case _UNPACK_SEQUENCE: { + for (int case_gen_i = 0; case_gen_i < (oparg); case_gen_i++) { + *(stack_pointer + case_gen_i) = sym_init_unknown(ctx); + if(*(stack_pointer + case_gen_i) == NULL) goto error; + } + stack_pointer += -1 + oparg; + break; + } + + case _UNPACK_SEQUENCE_TWO_TUPLE: { + for (int case_gen_i = 0; case_gen_i < (oparg); case_gen_i++) { + *(stack_pointer + case_gen_i) = sym_init_unknown(ctx); + if(*(stack_pointer + case_gen_i) == NULL) goto error; + } + stack_pointer += -1 + oparg; + break; + } + + case _UNPACK_SEQUENCE_TUPLE: { + for (int case_gen_i = 0; case_gen_i < (oparg); case_gen_i++) { + *(stack_pointer + case_gen_i) = sym_init_unknown(ctx); + if(*(stack_pointer + case_gen_i) == NULL) goto error; + } + stack_pointer += -1 + oparg; + break; + } + + case _UNPACK_SEQUENCE_LIST: { + for (int case_gen_i = 0; case_gen_i < (oparg); case_gen_i++) { + *(stack_pointer + case_gen_i) = sym_init_unknown(ctx); + if(*(stack_pointer + case_gen_i) == NULL) goto error; + } + stack_pointer += -1 + oparg; + break; + } + + case _UNPACK_EX: { + for (int case_gen_i = 0; case_gen_i < (oparg & 0xFF); case_gen_i++) { + *(stack_pointer + case_gen_i) = sym_init_unknown(ctx); + if(*(stack_pointer + case_gen_i) == NULL) goto error; + } + for (int case_gen_i = 0; case_gen_i < (oparg >> 8); case_gen_i++) { + *(stack_pointer + case_gen_i) = sym_init_unknown(ctx); + if(*(stack_pointer + case_gen_i) == NULL) goto error; + } + stack_pointer += (oparg >> 8) + (oparg & 0xFF); + break; + } + + case _STORE_ATTR: { + stack_pointer += -2; + break; + } + + case _DELETE_ATTR: { + stack_pointer += -1; + break; + } + + case _STORE_GLOBAL: { + stack_pointer += -1; + break; + } + + case _DELETE_GLOBAL: { + break; + } + + case _LOAD_LOCALS: { + _Py_UOpsSymType *__locals_; + __locals_ = sym_init_unknown(ctx); + if(__locals_ == NULL) goto error; + stack_pointer[0] = __locals_; + stack_pointer += 1; + break; + } + + case _LOAD_FROM_DICT_OR_GLOBALS: { + _Py_UOpsSymType *__v_; + __v_ = sym_init_unknown(ctx); + if(__v_ == NULL) goto error; + stack_pointer[-1] = __v_; + break; + } + + case _LOAD_NAME: { + _Py_UOpsSymType *__v_; + __v_ = sym_init_unknown(ctx); + if(__v_ == NULL) goto error; + stack_pointer[0] = __v_; + stack_pointer += 1; + break; + } + + case _LOAD_GLOBAL: { + _Py_UOpsSymType *__res_; + _Py_UOpsSymType *__null_ = NULL; + __null_ = sym_init_push_null(ctx); + if (__null_ == NULL) { goto error; } + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[0] = __res_; + if (oparg & 1) stack_pointer[1] = __null_; + stack_pointer += 1 + (oparg & 1); + break; + } + + case _GUARD_GLOBALS_VERSION: { + break; + } + + case _GUARD_BUILTINS_VERSION: { + break; + } + + case _LOAD_GLOBAL_MODULE: { + _Py_UOpsSymType *__res_; + _Py_UOpsSymType *__null_ = NULL; + __null_ = sym_init_push_null(ctx); + if (__null_ == NULL) { goto error; } + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[0] = __res_; + if (oparg & 1) stack_pointer[1] = __null_; + stack_pointer += 1 + (oparg & 1); + break; + } + + case _LOAD_GLOBAL_BUILTINS: { + _Py_UOpsSymType *__res_; + _Py_UOpsSymType *__null_ = NULL; + __null_ = sym_init_push_null(ctx); + if (__null_ == NULL) { goto error; } + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[0] = __res_; + if (oparg & 1) stack_pointer[1] = __null_; + stack_pointer += 1 + (oparg & 1); + break; + } + + case _DELETE_FAST: { + break; + } + + case _MAKE_CELL: { + break; + } + + case _DELETE_DEREF: { + break; + } + + case _LOAD_FROM_DICT_OR_DEREF: { + _Py_UOpsSymType *__value_; + __value_ = sym_init_unknown(ctx); + if(__value_ == NULL) goto error; + stack_pointer[-1] = __value_; + break; + } + + case _LOAD_DEREF: { + _Py_UOpsSymType *__value_; + __value_ = sym_init_unknown(ctx); + if(__value_ == NULL) goto error; + stack_pointer[0] = __value_; + stack_pointer += 1; + break; + } + + case _STORE_DEREF: { + stack_pointer += -1; + break; + } + + case _COPY_FREE_VARS: { + break; + } + + case _BUILD_STRING: { + _Py_UOpsSymType *__str_; + __str_ = sym_init_unknown(ctx); + if(__str_ == NULL) goto error; + stack_pointer[-oparg] = __str_; + stack_pointer += 1 - oparg; + break; + } + + case _BUILD_TUPLE: { + _Py_UOpsSymType *__tup_; + __tup_ = sym_init_unknown(ctx); + if(__tup_ == NULL) goto error; + stack_pointer[-oparg] = __tup_; + stack_pointer += 1 - oparg; + break; + } + + case _BUILD_LIST: { + _Py_UOpsSymType *__list_; + __list_ = sym_init_unknown(ctx); + if(__list_ == NULL) goto error; + stack_pointer[-oparg] = __list_; + stack_pointer += 1 - oparg; + break; + } + + case _LIST_EXTEND: { + stack_pointer += -1; + break; + } + + case _SET_UPDATE: { + stack_pointer += -1; + break; + } + + case _BUILD_SET: { + _Py_UOpsSymType *__set_; + __set_ = sym_init_unknown(ctx); + if(__set_ == NULL) goto error; + stack_pointer[-oparg] = __set_; + stack_pointer += 1 - oparg; + break; + } + + case _BUILD_MAP: { + _Py_UOpsSymType *__map_; + __map_ = sym_init_unknown(ctx); + if(__map_ == NULL) goto error; + stack_pointer[-oparg*2] = __map_; + stack_pointer += 1 - oparg*2; + break; + } + + case _SETUP_ANNOTATIONS: { + break; + } + + case _BUILD_CONST_KEY_MAP: { + _Py_UOpsSymType *__map_; + __map_ = sym_init_unknown(ctx); + if(__map_ == NULL) goto error; + stack_pointer[-1 - oparg] = __map_; + stack_pointer += -oparg; + break; + } + + case _DICT_UPDATE: { + stack_pointer += -1; + break; + } + + case _DICT_MERGE: { + stack_pointer += -1; + break; + } + + case _MAP_ADD: { + stack_pointer += -2; + break; + } + + /* _INSTRUMENTED_LOAD_SUPER_ATTR is not a viable micro-op for tier 2 */ + + case _LOAD_SUPER_ATTR_ATTR: { + _Py_UOpsSymType *__attr_; + __attr_ = sym_init_unknown(ctx); + if(__attr_ == NULL) goto error; + stack_pointer[-3] = __attr_; + stack_pointer += -2 + ((0) ? 1 : 0); + break; + } + + case _LOAD_SUPER_ATTR_METHOD: { + _Py_UOpsSymType *__attr_; + _Py_UOpsSymType *__self_or_null_; + __attr_ = sym_init_unknown(ctx); + if(__attr_ == NULL) goto error; + __self_or_null_ = sym_init_unknown(ctx); + if(__self_or_null_ == NULL) goto error; + stack_pointer[-3] = __attr_; + stack_pointer[-2] = __self_or_null_; + stack_pointer += -1; + break; + } + + case _LOAD_ATTR: { + _Py_UOpsSymType *__attr_; + _Py_UOpsSymType *__self_or_null_ = NULL; + __attr_ = sym_init_unknown(ctx); + if(__attr_ == NULL) goto error; + __self_or_null_ = sym_init_unknown(ctx); + if(__self_or_null_ == NULL) goto error; + sym_set_type(__self_or_null_, SELF_OR_NULL, 0); + stack_pointer[-1] = __attr_; + if (oparg & 1) stack_pointer[0] = __self_or_null_; + stack_pointer += (oparg & 1); + break; + } + + case _GUARD_TYPE_VERSION: { + _Py_UOpsSymType *__owner_; + __owner_ = stack_pointer[-1]; + // Constant evaluation + uint32_t type_version = (uint32_t)CURRENT_OPERAND(); + if (is_const(__owner_)) { + PyObject *owner; + owner = get_const(__owner_); + PyTypeObject *tp = Py_TYPE(owner); + assert(type_version != 0); + if (tp->tp_version_tag != type_version) goto error; + + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + // Type guard elimination + if (sym_matches_type((_Py_UOpsSymType *)__owner_, GUARD_TYPE_VERSION_TYPE, (uint32_t)type_version)) { + DPRINTF(2, "type propagation eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + else { + // Type propagation + sym_set_type((_Py_UOpsSymType *)__owner_, GUARD_TYPE_VERSION_TYPE, (uint32_t)type_version); + } + break; + } + + case _CHECK_MANAGED_OBJECT_HAS_VALUES: { + break; + } + + case _LOAD_ATTR_INSTANCE_VALUE: { + _Py_UOpsSymType *__attr_; + _Py_UOpsSymType *__null_ = NULL; + __null_ = sym_init_push_null(ctx); + if (__null_ == NULL) { goto error; } + __attr_ = sym_init_unknown(ctx); + if(__attr_ == NULL) goto error; + stack_pointer[-1] = __attr_; + if (oparg & 1) stack_pointer[0] = __null_; + stack_pointer += (oparg & 1); + break; + } + + case _CHECK_ATTR_MODULE: { + _Py_UOpsSymType *__owner_; + __owner_ = stack_pointer[-1]; + // Constant evaluation + uint32_t type_version = (uint32_t)CURRENT_OPERAND(); + if (is_const(__owner_)) { + PyObject *owner; + owner = get_const(__owner_); + if (!PyModule_CheckExact(owner)) goto error; + PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; + assert(dict != NULL); + if (dict->ma_keys->dk_version != type_version) goto error; + + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + break; + } + + case _LOAD_ATTR_MODULE: { + _Py_UOpsSymType *__attr_; + _Py_UOpsSymType *__null_ = NULL; + __null_ = sym_init_push_null(ctx); + if (__null_ == NULL) { goto error; } + __attr_ = sym_init_unknown(ctx); + if(__attr_ == NULL) goto error; + stack_pointer[-1] = __attr_; + if (oparg & 1) stack_pointer[0] = __null_; + stack_pointer += (oparg & 1); + break; + } + + case _CHECK_ATTR_WITH_HINT: { + _Py_UOpsSymType *__owner_; + __owner_ = stack_pointer[-1]; + // Constant evaluation + if (is_const(__owner_)) { + PyObject *owner; + owner = get_const(__owner_); + assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + if (_PyDictOrValues_IsValues(dorv)) goto error; + PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); + if (dict == NULL) goto error; + assert(PyDict_CheckExact((PyObject *)dict)); + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + break; + } + + case _LOAD_ATTR_WITH_HINT: { + _Py_UOpsSymType *__attr_; + _Py_UOpsSymType *__null_ = NULL; + __null_ = sym_init_push_null(ctx); + if (__null_ == NULL) { goto error; } + __attr_ = sym_init_unknown(ctx); + if(__attr_ == NULL) goto error; + stack_pointer[-1] = __attr_; + if (oparg & 1) stack_pointer[0] = __null_; + stack_pointer += (oparg & 1); + break; + } + + case _LOAD_ATTR_SLOT: { + _Py_UOpsSymType *__attr_; + _Py_UOpsSymType *__null_ = NULL; + __null_ = sym_init_push_null(ctx); + if (__null_ == NULL) { goto error; } + __attr_ = sym_init_unknown(ctx); + if(__attr_ == NULL) goto error; + stack_pointer[-1] = __attr_; + if (oparg & 1) stack_pointer[0] = __null_; + stack_pointer += (oparg & 1); + break; + } + + case _CHECK_ATTR_CLASS: { + _Py_UOpsSymType *__owner_; + __owner_ = stack_pointer[-1]; + // Constant evaluation + uint32_t type_version = (uint32_t)CURRENT_OPERAND(); + if (is_const(__owner_)) { + PyObject *owner; + owner = get_const(__owner_); + if (!PyType_Check(owner)) goto error; + assert(type_version != 0); + if (((PyTypeObject *)owner)->tp_version_tag != type_version) goto error; + + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + break; + } + + case _LOAD_ATTR_CLASS: { + _Py_UOpsSymType *__attr_; + _Py_UOpsSymType *__null_ = NULL; + __null_ = sym_init_push_null(ctx); + if (__null_ == NULL) { goto error; } + __attr_ = sym_init_unknown(ctx); + if(__attr_ == NULL) goto error; + stack_pointer[-1] = __attr_; + if (oparg & 1) stack_pointer[0] = __null_; + stack_pointer += (oparg & 1); + break; + } + + /* _LOAD_ATTR_PROPERTY is not a viable micro-op for tier 2 */ + + /* _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN is not a viable micro-op for tier 2 */ + + case _GUARD_DORV_VALUES: { + _Py_UOpsSymType *__owner_; + __owner_ = stack_pointer[-1]; + // Constant evaluation + if (is_const(__owner_)) { + PyObject *owner; + owner = get_const(__owner_); + assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + if (!_PyDictOrValues_IsValues(dorv)) goto error; + + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + // Type guard elimination + if (sym_matches_type((_Py_UOpsSymType *)__owner_, GUARD_DORV_VALUES_TYPE, (uint32_t)0)) { + DPRINTF(2, "type propagation eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + else { + // Type propagation + sym_set_type((_Py_UOpsSymType *)__owner_, GUARD_DORV_VALUES_TYPE, (uint32_t)0); + } + break; + } + + case _STORE_ATTR_INSTANCE_VALUE: { + stack_pointer += -2; + break; + } + + /* _STORE_ATTR_WITH_HINT is not a viable micro-op for tier 2 */ + + case _STORE_ATTR_SLOT: { + stack_pointer += -2; + break; + } + + case _COMPARE_OP: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + case _COMPARE_OP_FLOAT: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + case _COMPARE_OP_INT: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + case _COMPARE_OP_STR: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + case _IS_OP: { + _Py_UOpsSymType *__b_; + __b_ = sym_init_unknown(ctx); + if(__b_ == NULL) goto error; + stack_pointer[-2] = __b_; + stack_pointer += -1; + break; + } + + case _CONTAINS_OP: { + _Py_UOpsSymType *__b_; + __b_ = sym_init_unknown(ctx); + if(__b_ == NULL) goto error; + stack_pointer[-2] = __b_; + stack_pointer += -1; + break; + } + + case _CHECK_EG_MATCH: { + _Py_UOpsSymType *__rest_; + _Py_UOpsSymType *__match_; + __rest_ = sym_init_unknown(ctx); + if(__rest_ == NULL) goto error; + __match_ = sym_init_unknown(ctx); + if(__match_ == NULL) goto error; + stack_pointer[-2] = __rest_; + stack_pointer[-1] = __match_; + break; + } + + case _CHECK_EXC_MATCH: { + _Py_UOpsSymType *__b_; + __b_ = sym_init_unknown(ctx); + if(__b_ == NULL) goto error; + stack_pointer[-1] = __b_; + break; + } + + /* _JUMP_BACKWARD is not a viable micro-op for tier 2 */ + + /* _POP_JUMP_IF_FALSE is not a viable micro-op for tier 2 */ + + /* _POP_JUMP_IF_TRUE is not a viable micro-op for tier 2 */ + + case _IS_NONE: { + _Py_UOpsSymType *__b_; + __b_ = sym_init_unknown(ctx); + if(__b_ == NULL) goto error; + stack_pointer[-1] = __b_; + break; + } + + case _GET_LEN: { + _Py_UOpsSymType *__len_o_; + __len_o_ = sym_init_unknown(ctx); + if(__len_o_ == NULL) goto error; + stack_pointer[0] = __len_o_; + stack_pointer += 1; + break; + } + + case _MATCH_CLASS: { + _Py_UOpsSymType *__attrs_; + __attrs_ = sym_init_unknown(ctx); + if(__attrs_ == NULL) goto error; + stack_pointer[-3] = __attrs_; + stack_pointer += -2; + break; + } + + case _MATCH_MAPPING: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[0] = __res_; + stack_pointer += 1; + break; + } + + case _MATCH_SEQUENCE: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[0] = __res_; + stack_pointer += 1; + break; + } + + case _MATCH_KEYS: { + _Py_UOpsSymType *__values_or_none_; + __values_or_none_ = sym_init_unknown(ctx); + if(__values_or_none_ == NULL) goto error; + stack_pointer[0] = __values_or_none_; + stack_pointer += 1; + break; + } + + case _GET_ITER: { + _Py_UOpsSymType *__iter_; + __iter_ = sym_init_unknown(ctx); + if(__iter_ == NULL) goto error; + stack_pointer[-1] = __iter_; + break; + } + + case _GET_YIELD_FROM_ITER: { + _Py_UOpsSymType *__iter_; + __iter_ = sym_init_unknown(ctx); + if(__iter_ == NULL) goto error; + stack_pointer[-1] = __iter_; + break; + } + + /* _FOR_ITER is not a viable micro-op for tier 2 */ + + case _FOR_ITER_TIER_TWO: { + _Py_UOpsSymType *__next_; + __next_ = sym_init_unknown(ctx); + if(__next_ == NULL) goto error; + stack_pointer[0] = __next_; + stack_pointer += 1; + break; + } + + /* _INSTRUMENTED_FOR_ITER is not a viable micro-op for tier 2 */ + + case _ITER_CHECK_LIST: { + _Py_UOpsSymType *__iter_; + __iter_ = stack_pointer[-1]; + // Constant evaluation + if (is_const(__iter_)) { + PyObject *iter; + iter = get_const(__iter_); + if (Py_TYPE(iter) != &PyListIter_Type) goto error; + + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + break; + } + + /* _ITER_JUMP_LIST is not a viable micro-op for tier 2 */ + + case _GUARD_NOT_EXHAUSTED_LIST: { + _Py_UOpsSymType *__iter_; + __iter_ = stack_pointer[-1]; + // Constant evaluation + if (is_const(__iter_)) { + PyObject *iter; + iter = get_const(__iter_); + _PyListIterObject *it = (_PyListIterObject *)iter; + assert(Py_TYPE(iter) == &PyListIter_Type); + PyListObject *seq = it->it_seq; + if (seq == NULL) goto error; + if (it->it_index >= PyList_GET_SIZE(seq)) goto error; + + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + break; + } + + case _ITER_NEXT_LIST: { + _Py_UOpsSymType *__next_; + __next_ = sym_init_unknown(ctx); + if(__next_ == NULL) goto error; + stack_pointer[0] = __next_; + stack_pointer += 1; + break; + } + + case _ITER_CHECK_TUPLE: { + _Py_UOpsSymType *__iter_; + __iter_ = stack_pointer[-1]; + // Constant evaluation + if (is_const(__iter_)) { + PyObject *iter; + iter = get_const(__iter_); + if (Py_TYPE(iter) != &PyTupleIter_Type) goto error; + + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + break; + } + + /* _ITER_JUMP_TUPLE is not a viable micro-op for tier 2 */ + + case _GUARD_NOT_EXHAUSTED_TUPLE: { + _Py_UOpsSymType *__iter_; + __iter_ = stack_pointer[-1]; + // Constant evaluation + if (is_const(__iter_)) { + PyObject *iter; + iter = get_const(__iter_); + _PyTupleIterObject *it = (_PyTupleIterObject *)iter; + assert(Py_TYPE(iter) == &PyTupleIter_Type); + PyTupleObject *seq = it->it_seq; + if (seq == NULL) goto error; + if (it->it_index >= PyTuple_GET_SIZE(seq)) goto error; + + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + break; + } + + case _ITER_NEXT_TUPLE: { + _Py_UOpsSymType *__next_; + __next_ = sym_init_unknown(ctx); + if(__next_ == NULL) goto error; + stack_pointer[0] = __next_; + stack_pointer += 1; + break; + } + + case _ITER_CHECK_RANGE: { + _Py_UOpsSymType *__iter_; + __iter_ = stack_pointer[-1]; + // Constant evaluation + if (is_const(__iter_)) { + PyObject *iter; + iter = get_const(__iter_); + _PyRangeIterObject *r = (_PyRangeIterObject *)iter; + if (Py_TYPE(r) != &PyRangeIter_Type) goto error; + + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + break; + } + + /* _ITER_JUMP_RANGE is not a viable micro-op for tier 2 */ + + case _GUARD_NOT_EXHAUSTED_RANGE: { + _Py_UOpsSymType *__iter_; + __iter_ = stack_pointer[-1]; + // Constant evaluation + if (is_const(__iter_)) { + PyObject *iter; + iter = get_const(__iter_); + _PyRangeIterObject *r = (_PyRangeIterObject *)iter; + assert(Py_TYPE(r) == &PyRangeIter_Type); + if (r->len <= 0) goto error; + + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + break; + } + + case _ITER_NEXT_RANGE: { + _Py_UOpsSymType *__next_; + __next_ = sym_init_unknown(ctx); + if(__next_ == NULL) goto error; + sym_set_type(__next_, PYLONG_TYPE, 0); + stack_pointer[0] = __next_; + stack_pointer += 1; + break; + } + + /* _FOR_ITER_GEN is not a viable micro-op for tier 2 */ + + case _BEFORE_ASYNC_WITH: { + _Py_UOpsSymType *__exit_; + _Py_UOpsSymType *__res_; + __exit_ = sym_init_unknown(ctx); + if(__exit_ == NULL) goto error; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-1] = __exit_; + stack_pointer[0] = __res_; + stack_pointer += 1; + break; + } + + case _BEFORE_WITH: { + _Py_UOpsSymType *__exit_; + _Py_UOpsSymType *__res_; + __exit_ = sym_init_unknown(ctx); + if(__exit_ == NULL) goto error; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-1] = __exit_; + stack_pointer[0] = __res_; + stack_pointer += 1; + break; + } + + case _WITH_EXCEPT_START: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[0] = __res_; + stack_pointer += 1; + break; + } + + case _PUSH_EXC_INFO: { + _Py_UOpsSymType *__prev_exc_; + _Py_UOpsSymType *__new_exc_; + __prev_exc_ = sym_init_unknown(ctx); + if(__prev_exc_ == NULL) goto error; + __new_exc_ = sym_init_unknown(ctx); + if(__new_exc_ == NULL) goto error; + stack_pointer[-1] = __prev_exc_; + stack_pointer[0] = __new_exc_; + stack_pointer += 1; + break; + } + + case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT: { + _Py_UOpsSymType *__owner_; + __owner_ = stack_pointer[-1]; + // Constant evaluation + if (is_const(__owner_)) { + PyObject *owner; + owner = get_const(__owner_); + assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner); + if (!_PyDictOrValues_IsValues(*dorv) && !_PyObject_MakeInstanceAttributesFromDict(owner, dorv)) goto error; + + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + break; + } + + case _GUARD_KEYS_VERSION: { + _Py_UOpsSymType *__owner_; + __owner_ = stack_pointer[-1]; + // Constant evaluation + uint32_t keys_version = (uint32_t)CURRENT_OPERAND(); + if (is_const(__owner_)) { + PyObject *owner; + owner = get_const(__owner_); + PyTypeObject *owner_cls = Py_TYPE(owner); + PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; + if (owner_heap_type->ht_cached_keys->dk_version != keys_version) goto error; + + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + // Type guard elimination + if (sym_matches_type((_Py_UOpsSymType *)__owner_, GUARD_KEYS_VERSION_TYPE, (uint32_t)keys_version)) { + DPRINTF(2, "type propagation eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + else { + // Type propagation + sym_set_type((_Py_UOpsSymType *)__owner_, GUARD_KEYS_VERSION_TYPE, (uint32_t)keys_version); + } + break; + } + + case _LOAD_ATTR_METHOD_WITH_VALUES: { + _Py_UOpsSymType *__attr_; + _Py_UOpsSymType *__self_ = NULL; + __attr_ = sym_init_unknown(ctx); + if(__attr_ == NULL) goto error; + __self_ = sym_init_unknown(ctx); + if(__self_ == NULL) goto error; + stack_pointer[-1] = __attr_; + if (1) stack_pointer[0] = __self_; + stack_pointer += ((1) ? 1 : 0); + break; + } + + case _LOAD_ATTR_METHOD_NO_DICT: { + _Py_UOpsSymType *__attr_; + _Py_UOpsSymType *__self_ = NULL; + __attr_ = sym_init_unknown(ctx); + if(__attr_ == NULL) goto error; + __self_ = sym_init_unknown(ctx); + if(__self_ == NULL) goto error; + stack_pointer[-1] = __attr_; + if (1) stack_pointer[0] = __self_; + stack_pointer += ((1) ? 1 : 0); + break; + } + + case _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: { + _Py_UOpsSymType *__attr_; + __attr_ = sym_init_unknown(ctx); + if(__attr_ == NULL) goto error; + stack_pointer[-1] = __attr_; + stack_pointer += ((0) ? 1 : 0); + break; + } + + case _LOAD_ATTR_NONDESCRIPTOR_NO_DICT: { + _Py_UOpsSymType *__attr_; + __attr_ = sym_init_unknown(ctx); + if(__attr_ == NULL) goto error; + stack_pointer[-1] = __attr_; + stack_pointer += ((0) ? 1 : 0); + break; + } + + case _CHECK_ATTR_METHOD_LAZY_DICT: { + _Py_UOpsSymType *__owner_; + __owner_ = stack_pointer[-1]; + // Constant evaluation + if (is_const(__owner_)) { + PyObject *owner; + owner = get_const(__owner_); + Py_ssize_t dictoffset = Py_TYPE(owner)->tp_dictoffset; + assert(dictoffset > 0); + PyObject *dict = *(PyObject **)((char *)owner + dictoffset); + /* This object has a __dict__, just not yet created */ + if (dict != NULL) goto error; + + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + break; + } + + case _LOAD_ATTR_METHOD_LAZY_DICT: { + _Py_UOpsSymType *__attr_; + _Py_UOpsSymType *__self_ = NULL; + __attr_ = sym_init_unknown(ctx); + if(__attr_ == NULL) goto error; + __self_ = sym_init_unknown(ctx); + if(__self_ == NULL) goto error; + stack_pointer[-1] = __attr_; + if (1) stack_pointer[0] = __self_; + stack_pointer += ((1) ? 1 : 0); + break; + } + + /* _INSTRUMENTED_CALL is not a viable micro-op for tier 2 */ + + /* _CALL is not a viable micro-op for tier 2 */ + + case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: { + _Py_UOpsSymType *__null_; + _Py_UOpsSymType *__callable_; + __null_ = stack_pointer[-1 - oparg]; + __callable_ = stack_pointer[-2 - oparg]; + // Constant evaluation + if (is_const(__callable_) && is_const(__null_)) { + PyObject *null; + PyObject *callable; + callable = get_const(__callable_); + null = get_const(__null_); + if (null != NULL) goto error; + if (Py_TYPE(callable) != &PyMethod_Type) goto error; + + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + // Type guard elimination + if (sym_matches_type((_Py_UOpsSymType *)__callable_, PYMETHOD_TYPE, (uint32_t)0) && sym_matches_type((_Py_UOpsSymType *)__null_, NULL_TYPE, (uint32_t)0)) { + DPRINTF(2, "type propagation eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + else { + // Type propagation + sym_set_type((_Py_UOpsSymType *)__callable_, PYMETHOD_TYPE, (uint32_t)0); + sym_set_type((_Py_UOpsSymType *)__null_, NULL_TYPE, (uint32_t)0); + } + break; + } + + case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: { + _Py_UOpsSymType *__func_; + _Py_UOpsSymType *__self_; + __func_ = sym_init_unknown(ctx); + if(__func_ == NULL) goto error; + __self_ = sym_init_unknown(ctx); + if(__self_ == NULL) goto error; + stack_pointer[-2 - oparg] = __func_; + stack_pointer[-1 - oparg] = __self_; + break; + } + + case _CHECK_FUNCTION_EXACT_ARGS: { + _Py_UOpsSymType *__self_or_null_; + _Py_UOpsSymType *__callable_; + __self_or_null_ = stack_pointer[-1 - oparg]; + __callable_ = stack_pointer[-2 - oparg]; + // Constant evaluation + uint32_t func_version = (uint32_t)CURRENT_OPERAND(); + if (is_const(__callable_) && is_const(__self_or_null_)) { + PyObject *self_or_null; + PyObject *callable; + callable = get_const(__callable_); + self_or_null = get_const(__self_or_null_); + if (!PyFunction_Check(callable)) goto error; + PyFunctionObject *func = (PyFunctionObject *)callable; + if (func->func_version != func_version) goto error; + PyCodeObject *code = (PyCodeObject *)func->func_code; + if (code->co_argcount != oparg + (self_or_null != NULL)) goto error; + + DPRINTF(3, "const eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + // Type guard elimination + if (sym_matches_type((_Py_UOpsSymType *)__callable_, PYFUNCTION_TYPE_VERSION_TYPE, (uint32_t)func_version)) { + DPRINTF(2, "type propagation eliminated guard\n"); + new_inst.opcode = _NOP; + break; + } + else { + // Type propagation + sym_set_type((_Py_UOpsSymType *)__callable_, PYFUNCTION_TYPE_VERSION_TYPE, (uint32_t)func_version); + } + break; + } + + case _CHECK_STACK_SPACE: { + break; + } + + /* _CALL_PY_WITH_DEFAULTS is not a viable micro-op for tier 2 */ + + case _CALL_TYPE_1: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2 - oparg] = __res_; + stack_pointer += -1 - oparg; + break; + } + + case _CALL_STR_1: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2 - oparg] = __res_; + stack_pointer += -1 - oparg; + break; + } + + case _CALL_TUPLE_1: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2 - oparg] = __res_; + stack_pointer += -1 - oparg; + break; + } + + /* _CALL_ALLOC_AND_ENTER_INIT is not a viable micro-op for tier 2 */ + + case _EXIT_INIT_CHECK: { + stack_pointer += -1; + break; + } + + case _CALL_BUILTIN_CLASS: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2 - oparg] = __res_; + stack_pointer += -1 - oparg; + break; + } + + case _CALL_BUILTIN_O: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2 - oparg] = __res_; + stack_pointer += -1 - oparg; + break; + } + + case _CALL_BUILTIN_FAST: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2 - oparg] = __res_; + stack_pointer += -1 - oparg; + break; + } + + case _CALL_BUILTIN_FAST_WITH_KEYWORDS: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2 - oparg] = __res_; + stack_pointer += -1 - oparg; + break; + } + + case _CALL_LEN: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2 - oparg] = __res_; + stack_pointer += -1 - oparg; + break; + } + + case _CALL_ISINSTANCE: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2 - oparg] = __res_; + stack_pointer += -1 - oparg; + break; + } + + case _CALL_METHOD_DESCRIPTOR_O: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2 - oparg] = __res_; + stack_pointer += -1 - oparg; + break; + } + + case _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2 - oparg] = __res_; + stack_pointer += -1 - oparg; + break; + } + + case _CALL_METHOD_DESCRIPTOR_NOARGS: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2 - oparg] = __res_; + stack_pointer += -1 - oparg; + break; + } + + case _CALL_METHOD_DESCRIPTOR_FAST: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2 - oparg] = __res_; + stack_pointer += -1 - oparg; + break; + } + + /* _INSTRUMENTED_CALL_KW is not a viable micro-op for tier 2 */ + + /* _CALL_KW is not a viable micro-op for tier 2 */ + + /* _INSTRUMENTED_CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ + + /* _CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ + + case _MAKE_FUNCTION: { + _Py_UOpsSymType *__func_; + __func_ = sym_init_unknown(ctx); + if(__func_ == NULL) goto error; + stack_pointer[-1] = __func_; + break; + } + + case _SET_FUNCTION_ATTRIBUTE: { + _Py_UOpsSymType *__func_; + __func_ = sym_init_unknown(ctx); + if(__func_ == NULL) goto error; + stack_pointer[-2] = __func_; + stack_pointer += -1; + break; + } + + case _BUILD_SLICE: { + _Py_UOpsSymType *__slice_; + __slice_ = sym_init_unknown(ctx); + if(__slice_ == NULL) goto error; + stack_pointer[-2 - ((oparg == 3) ? 1 : 0)] = __slice_; + stack_pointer += -1 - ((oparg == 3) ? 1 : 0); + break; + } + + case _CONVERT_VALUE: { + _Py_UOpsSymType *__result_; + __result_ = sym_init_unknown(ctx); + if(__result_ == NULL) goto error; + stack_pointer[-1] = __result_; + break; + } + + case _FORMAT_SIMPLE: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-1] = __res_; + break; + } + + case _FORMAT_WITH_SPEC: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + case _BINARY_OP: { + _Py_UOpsSymType *__res_; + __res_ = sym_init_unknown(ctx); + if(__res_ == NULL) goto error; + stack_pointer[-2] = __res_; + stack_pointer += -1; + break; + } + + case _SWAP: { + _Py_UOpsSymType *__top_; + _Py_UOpsSymType *__bottom_; + __top_ = stack_pointer[-1]; + __bottom_ = stack_pointer[-2 - (oparg-2)]; + (void)__bottom_; + (void)__top_; + stack_pointer[-2 - (oparg-2)] = __top_; + stack_pointer[-1] = __bottom_; + break; + } + + /* _INSTRUMENTED_INSTRUCTION is not a viable micro-op for tier 2 */ + + /* _INSTRUMENTED_JUMP_FORWARD is not a viable micro-op for tier 2 */ + + /* _INSTRUMENTED_JUMP_BACKWARD is not a viable micro-op for tier 2 */ + + /* _INSTRUMENTED_POP_JUMP_IF_TRUE is not a viable micro-op for tier 2 */ + + /* _INSTRUMENTED_POP_JUMP_IF_FALSE is not a viable micro-op for tier 2 */ + + /* _INSTRUMENTED_POP_JUMP_IF_NONE is not a viable micro-op for tier 2 */ + + /* _INSTRUMENTED_POP_JUMP_IF_NOT_NONE is not a viable micro-op for tier 2 */ + + case _GUARD_IS_TRUE_POP: { + stack_pointer += -1; + break; + } + + case _GUARD_IS_FALSE_POP: { + stack_pointer += -1; + break; + } + + case _GUARD_IS_NONE_POP: { + stack_pointer += -1; + break; + } + + case _GUARD_IS_NOT_NONE_POP: { + stack_pointer += -1; + break; + } + + case _JUMP_TO_TOP: { + break; + } + + case _EXIT_TRACE: { + break; + } + + case _JUMP_ABSOLUTE: { + break; + } + + case _JUMP_ABSOLUTE_HEADER: { + break; + } + + case _INTERNAL_INCREMENT_OPT_COUNTER: { + stack_pointer += -1; + break; + } + + case _SHRINK_STACK: { + stack_pointer += -oparg; + break; + } + +#undef TIER_TWO diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 6fb4d719e43991..6e22f07b69ae2d 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -133,7 +133,7 @@ dummy_func( switch (opcode) { // BEGIN BYTECODES // - inst(NOP, (--)) { + pure inst(NOP, (--)) { } family(RESUME, 0) = { @@ -1859,7 +1859,7 @@ dummy_func( #endif /* ENABLE_SPECIALIZATION */ } - op(_LOAD_ATTR, (owner -- attr, self_or_null if (oparg & 1))) { + op(_LOAD_ATTR, (owner -- attr, self_or_null: &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. */ @@ -1877,7 +1877,7 @@ dummy_func( something was returned by a descriptor protocol). Set the second element of the stack to NULL, to signal CALL that it's not a method call. - NULL | meth | arg1 | ... | argN + meth | NULL | arg1 | ... | argN */ DECREF_INPUTS(); ERROR_IF(attr == NULL, error); @@ -2880,7 +2880,7 @@ dummy_func( exc_info->exc_value = Py_NewRef(new_exc); } - op(_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, (owner -- owner: &GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_TYPE)) { + op(_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, (owner -- owner)) { assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner); DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && !_PyObject_MakeInstanceAttributesFromDict(owner, dorv)); @@ -4065,28 +4065,36 @@ dummy_func( DEOPT_IF(1); } + op(_JUMP_ABSOLUTE, (--)) { + next_uop = current_executor->trace + oparg; + CHECK_EVAL_BREAKER(); + } + + op(_JUMP_ABSOLUTE_HEADER, (--)) { + } + op(_CHECK_VALIDITY, (--)) { TIER_TWO_ONLY DEOPT_IF(!current_executor->vm_data.valid); } - op(_LOAD_CONST_INLINE, (ptr/4 -- value)) { + pure op(_LOAD_CONST_INLINE, (ptr/4 -- value)) { TIER_TWO_ONLY value = Py_NewRef(ptr); } - op(_LOAD_CONST_INLINE_BORROW, (ptr/4 -- value)) { + pure op(_LOAD_CONST_INLINE_BORROW, (ptr/4 -- value)) { TIER_TWO_ONLY value = ptr; } - op(_LOAD_CONST_INLINE_WITH_NULL, (ptr/4 -- value, null)) { + pure op(_LOAD_CONST_INLINE_WITH_NULL, (ptr/4 -- value, null)) { TIER_TWO_ONLY value = Py_NewRef(ptr); null = NULL; } - op(_LOAD_CONST_INLINE_BORROW_WITH_NULL, (ptr/4 -- value, null)) { + pure op(_LOAD_CONST_INLINE_BORROW_WITH_NULL, (ptr/4 -- value, null)) { TIER_TWO_ONLY value = ptr; null = NULL; @@ -4108,6 +4116,10 @@ dummy_func( exe->count++; } + op(_SHRINK_STACK, (args[oparg] --)) { + DECREF_INPUTS(); + } + // END BYTECODES // diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 2d914b82dbf88f..e9bec214860ac1 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1598,7 +1598,7 @@ something was returned by a descriptor protocol). Set the second element of the stack to NULL, to signal CALL that it's not a method call. - NULL | meth | arg1 | ... | argN + meth | NULL | arg1 | ... | argN */ Py_DECREF(owner); if (attr == NULL) goto pop_1_error_tier_two; @@ -3384,6 +3384,17 @@ break; } + case _JUMP_ABSOLUTE: { + oparg = CURRENT_OPARG(); + next_uop = current_executor->trace + oparg; + CHECK_EVAL_BREAKER(); + break; + } + + case _JUMP_ABSOLUTE_HEADER: { + break; + } + case _CHECK_VALIDITY: { TIER_TWO_ONLY if (!current_executor->vm_data.valid) goto deoptimize; @@ -3459,4 +3470,15 @@ break; } + case _SHRINK_STACK: { + PyObject **args; + oparg = CURRENT_OPARG(); + args = &stack_pointer[-oparg]; + for (int _i = oparg; --_i >= 0;) { + Py_DECREF(args[_i]); + } + stack_pointer += -oparg; + break; + } + #undef TIER_TWO diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 16f1db30620d72..5487d8613591ec 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3431,7 +3431,7 @@ something was returned by a descriptor protocol). Set the second element of the stack to NULL, to signal CALL that it's not a method call. - NULL | meth | arg1 | ... | argN + meth | NULL | arg1 | ... | argN */ Py_DECREF(owner); if (attr == NULL) goto pop_1_error; diff --git a/Python/jit.c b/Python/jit.c index 22949c082da05a..308bde86d063df 100644 --- a/Python/jit.c +++ b/Python/jit.c @@ -298,6 +298,17 @@ emit(const StencilGroup *group, uint64_t patches[]) copy_and_patch((char *)patches[HoleValue_DATA], &group->data, patches); } +static size_t +calculate_jump_abs_offset(_PyUOpInstruction *trace, _PyUOpInstruction *jump_absolute) +{ + assert(jump_absolute->opcode == _JUMP_ABSOLUTE); + size_t total = 0; + for (int i = 0; i < jump_absolute->oparg; i++) { + total += stencil_groups[trace[i].opcode].code.body_size; + } + return total; +} + // Compiles executor in-place. Don't forget to call _PyJIT_Free later! int _PyJIT_Compile(_PyExecutorObject *executor, _PyUOpInstruction *trace, size_t length) @@ -329,7 +340,13 @@ _PyJIT_Compile(_PyExecutorObject *executor, _PyUOpInstruction *trace, size_t len // Think of patches as a dictionary mapping HoleValue to uint64_t: uint64_t patches[] = GET_PATCHES(); patches[HoleValue_CODE] = (uint64_t)code; - patches[HoleValue_CONTINUE] = (uint64_t)code + group->code.body_size; + if (instruction->opcode == _JUMP_ABSOLUTE) { + assert(i + 1 == length); + patches[HoleValue_CONTINUE] = (uint64_t)memory + calculate_jump_abs_offset(trace, instruction); + } + else { + patches[HoleValue_CONTINUE] = (uint64_t)code + group->code.body_size; + }; patches[HoleValue_DATA] = (uint64_t)data; patches[HoleValue_EXECUTOR] = (uint64_t)executor; patches[HoleValue_OPARG] = instruction->oparg; diff --git a/Python/optimizer.c b/Python/optimizer.c index d71ca0aef0e11a..d94f29c11da829 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -17,8 +17,6 @@ #include "pycore_uop_metadata.h" // Uop tables #undef NEED_OPCODE_METADATA -#define UOP_MAX_TRACE_LENGTH 512 - #define MAX_EXECUTORS_SIZE 256 @@ -223,8 +221,27 @@ static PyMethodDef executor_methods[] = { ///////////////////// Experimental UOp Optimizer ///////////////////// + +static void +clear_strong_refs_in_uops(_PyUOpInstruction *trace, Py_ssize_t uop_len) +{ + for (Py_ssize_t i = 0; i < uop_len; i++) { + if (trace[i].opcode == _LOAD_CONST_INLINE || + trace[i].opcode == _LOAD_CONST_INLINE_WITH_NULL) { + PyObject *c = (PyObject*)trace[i].operand; + Py_CLEAR(c); + } + if (trace[i].opcode == _JUMP_ABSOLUTE || + trace[i].opcode == _JUMP_TO_TOP || + trace[i].opcode == _EXIT_TRACE) { + return; + } + } +} + static void uop_dealloc(_PyExecutorObject *self) { + clear_strong_refs_in_uops(&self->trace[0], Py_SIZE(self)); _Py_ExecutorClear(self); #ifdef _Py_JIT _PyJIT_Free(self); @@ -312,8 +329,6 @@ BRANCH_TO_GUARD[4][2] = { [POP_JUMP_IF_NOT_NONE - POP_JUMP_IF_FALSE][1] = _GUARD_IS_NOT_NONE_POP, }; -#define TRACE_STACK_SIZE 5 - #define CONFIDENCE_RANGE 1000 #define CONFIDENCE_CUTOFF 333 @@ -327,10 +342,11 @@ BRANCH_TO_GUARD[4][2] = { #define ADD_TO_TRACE(OPCODE, OPARG, OPERAND, TARGET) \ DPRINTF(2, \ - " ADD_TO_TRACE(%s, %d, %" PRIu64 ")\n", \ + " ADD_TO_TRACE(%s, %d, %" PRIu64 ", %d)\n", \ _PyUOpName(OPCODE), \ (OPARG), \ - (uint64_t)(OPERAND)); \ + (uint64_t)(OPERAND), \ + TARGET); \ assert(trace_length < max_length); \ trace[trace_length].opcode = (OPCODE); \ trace[trace_length].oparg = (OPARG); \ @@ -720,13 +736,13 @@ compute_used(_PyUOpInstruction *buffer, uint32_t *used) { int count = 0; SET_BIT(used, 0); - for (int i = 0; i < UOP_MAX_TRACE_LENGTH; i++) { + for (int i = 0; i < UOP_MAX_TRACE_WORKING_LENGTH; i++) { if (!BIT_IS_SET(used, i)) { continue; } count++; int opcode = buffer[i].opcode; - if (opcode == _JUMP_TO_TOP || opcode == _EXIT_TRACE) { + if (opcode == _JUMP_TO_TOP || opcode == _EXIT_TRACE || opcode == _JUMP_ABSOLUTE) { continue; } /* All other micro-ops fall through, so i+1 is reachable */ @@ -752,7 +768,7 @@ compute_used(_PyUOpInstruction *buffer, uint32_t *used) static _PyExecutorObject * make_executor_from_uops(_PyUOpInstruction *buffer, _PyBloomFilter *dependencies) { - uint32_t used[(UOP_MAX_TRACE_LENGTH + 31)/32] = { 0 }; + uint32_t used[(UOP_MAX_TRACE_WORKING_LENGTH + 31)/32] = { 0 }; int length = compute_used(buffer, used); _PyExecutorObject *executor = PyObject_NewVar(_PyExecutorObject, &_PyUOpExecutor_Type, length); if (executor == NULL) { @@ -760,14 +776,15 @@ make_executor_from_uops(_PyUOpInstruction *buffer, _PyBloomFilter *dependencies) } int dest = length - 1; /* Scan backwards, so that we see the destinations of jumps before the jumps themselves. */ - for (int i = UOP_MAX_TRACE_LENGTH-1; i >= 0; i--) { + for (int i = UOP_MAX_TRACE_WORKING_LENGTH-1; i >= 0; i--) { if (!BIT_IS_SET(used, i)) { continue; } executor->trace[dest] = buffer[i]; int opcode = buffer[i].opcode; if (opcode == _POP_JUMP_IF_FALSE || - opcode == _POP_JUMP_IF_TRUE) + opcode == _POP_JUMP_IF_TRUE || + opcode == _JUMP_ABSOLUTE) { /* The oparg of the target will already have been set to its new offset */ int oparg = executor->trace[dest].oparg; @@ -779,6 +796,19 @@ make_executor_from_uops(_PyUOpInstruction *buffer, _PyBloomFilter *dependencies) dest--; } assert(dest == -1); + // Rewrite backward jumps + if (executor->trace[length-1].opcode == _JUMP_ABSOLUTE) { + bool found = false; + for (int end = length - 1; end >= 0; end--) { + if (executor->trace[end].opcode == _JUMP_ABSOLUTE_HEADER) { + executor->trace[length-1].oparg = end + 1; + found = true; + break; + } + } + assert(found); + (void)found; + } _Py_ExecutorInit(executor, dependencies); #ifdef Py_DEBUG char *python_lltrace = Py_GETENV("PYTHON_LLTRACE"); @@ -819,21 +849,19 @@ uop_optimize( { _PyBloomFilter dependencies; _Py_BloomFilter_Init(&dependencies); - _PyUOpInstruction buffer[UOP_MAX_TRACE_LENGTH]; + _PyUOpInstruction buffer[UOP_MAX_TRACE_WORKING_LENGTH]; int err = translate_bytecode_to_trace(frame, instr, buffer, UOP_MAX_TRACE_LENGTH, &dependencies); if (err <= 0) { // Error or nothing translated return err; } OPT_STAT_INC(traces_created); - char *uop_optimize = Py_GETENV("PYTHONUOPSOPTIMIZE"); - if (uop_optimize == NULL || *uop_optimize > '0') { - err = _Py_uop_analyze_and_optimize(frame, buffer, - UOP_MAX_TRACE_LENGTH, curr_stackentries, &dependencies); - if (err <= 0) { - return err; - } + err = _Py_uop_analyze_and_optimize(frame, buffer, + UOP_MAX_TRACE_WORKING_LENGTH, curr_stackentries, &dependencies); + if (err <= 0) { + return err; } + assert(err == 1); _PyExecutorObject *executor = make_executor_from_uops(buffer, &dependencies); if (executor == NULL) { return -1; diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 2cfbf4b349d0f5..774d956df0f516 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -1,3 +1,14 @@ +/* + * This file contains the optimizer for CPython uops. + * It performs a traditional data-flow analysis[1] over the trace of uops. + * Using the information gained, it chooses to emit, or skip certain instructions + * if possible. + * + * [1] For information on data-flow analysis, please see page 27 onwards in + * https://ilyasergey.net/CS4212/_static/lectures/PLDI-Week-12-dataflow.pdf + * Credits to the courses UPenn Compilers (CIS 341) and NUS Compiler Design (CS4212). + * + * */ #include "Python.h" #include "opcode.h" #include "pycore_dict.h" @@ -9,10 +20,893 @@ #include "pycore_dict.h" #include "pycore_long.h" #include "cpython/optimizer.h" +#include "pycore_optimizer.h" +#include "pycore_object.h" +#include "pycore_dict.h" +#include "pycore_function.h" +#include "pycore_uop_metadata.h" +#include "pycore_uop_ids.h" +#include "pycore_range.h" + +#include #include #include #include -#include "pycore_optimizer.h" + +// Holds locals, stack, locals, stack ... co_consts (in that order) +#define MAX_ABSTRACT_INTERP_SIZE 4096 + +#define OVERALLOCATE_FACTOR 5 + +#define TY_ARENA_SIZE (UOP_MAX_TRACE_WORKING_LENGTH * OVERALLOCATE_FACTOR) + +// Need extras for root frame and for overflow frame (see TRACE_STACK_PUSH()) +#define MAX_ABSTRACT_FRAME_DEPTH (TRACE_STACK_SIZE + 2) + +#ifdef Py_DEBUG + static const char *const DEBUG_ENV = "PYTHON_OPT_DEBUG"; + static inline int get_lltrace(void) { + char *uop_debug = Py_GETENV(DEBUG_ENV); + int lltrace = 0; + if (uop_debug != NULL && *uop_debug >= '0') { + lltrace = *uop_debug - '0'; // TODO: Parse an int and all that + } + return lltrace; + } + #define DPRINTF(level, ...) \ + if (get_lltrace() >= (level)) { printf(__VA_ARGS__); } +#else + #define DPRINTF(level, ...) +#endif + +// See the interpreter DSL in ./Tools/cases_generator/interpreter_definition.md for what these correspond to. +typedef enum { + // Types with refinement info + GUARD_KEYS_VERSION_TYPE = 0, + GUARD_TYPE_VERSION_TYPE = 1, + // You might think this actually needs to encode oparg + // info as well, see _CHECK_FUNCTION_EXACT_ARGS. + // However, since oparg is tied to code object is tied to function version, + // it should be safe if function version matches. + PYFUNCTION_TYPE_VERSION_TYPE = 2, + + // Types without refinement info + PYLONG_TYPE = 3, + PYFLOAT_TYPE = 4, + PYUNICODE_TYPE = 5, + NULL_TYPE = 6, + PYMETHOD_TYPE = 7, + GUARD_DORV_VALUES_TYPE = 8, + // Can't statically determine if self or null. + SELF_OR_NULL = 9, + + // Represents something from LOAD_CONST which is truly constant. + TRUE_CONST = 30, + INVALID_TYPE = 31, +} _Py_UOpsSymExprTypeEnum; + +#define MAX_TYPE_WITH_REFINEMENT PYFUNCTION_TYPE_VERSION_TYPE + +static const uint32_t IMMUTABLES = + ( + 1 << NULL_TYPE | + 1 << PYLONG_TYPE | + 1 << PYFLOAT_TYPE | + 1 << PYUNICODE_TYPE | + 1 << SELF_OR_NULL | + 1 << TRUE_CONST + ); + +typedef struct { + // bitmask of types + uint32_t types; + // refinement data for the types + uint64_t refinement[MAX_TYPE_WITH_REFINEMENT + 1]; + // constant propagated value (might be NULL) + PyObject *const_val; +} _Py_UOpsSymType; + + +typedef struct _Py_UOpsAbstractFrame { + // Symbolic version of co_consts + int sym_consts_len; + _Py_UOpsSymType **sym_consts; + // Max stacklen + int stack_len; + int locals_len; + + _Py_UOpsSymType **stack_pointer; + _Py_UOpsSymType **stack; + _Py_UOpsSymType **locals; +} _Py_UOpsAbstractFrame; + + +typedef struct ty_arena { + int ty_curr_number; + int ty_max_number; + _Py_UOpsSymType arena[TY_ARENA_SIZE]; +} ty_arena; + +typedef struct frequent_syms { + _Py_UOpsSymType *push_nulL_sym; +} frequent_syms; + +typedef struct uops_emitter { + _PyUOpInstruction *writebuffer; + _PyUOpInstruction *writebuffer_end; + int curr_i; +} uops_emitter; + +// Tier 2 types meta interpreter +typedef struct _Py_UOpsAbstractInterpContext { + PyObject_HEAD + // The current "executing" frame. + _Py_UOpsAbstractFrame *frame; + _Py_UOpsAbstractFrame frames[MAX_ABSTRACT_FRAME_DEPTH]; + int curr_frame_depth; + + // Arena for the symbolic types. + ty_arena t_arena; + + frequent_syms frequent_syms; + + uops_emitter emitter; + + _Py_UOpsSymType **n_consumed; + _Py_UOpsSymType **limit; + _Py_UOpsSymType *locals_and_stack[MAX_ABSTRACT_INTERP_SIZE]; +} _Py_UOpsAbstractInterpContext; + +static inline _Py_UOpsSymType* +sym_init_const(_Py_UOpsAbstractInterpContext *ctx, PyObject *const_val); + +static inline _Py_UOpsSymType ** +create_sym_consts(_Py_UOpsAbstractInterpContext *ctx, PyObject *co_consts) +{ + Py_ssize_t co_const_len = PyTuple_GET_SIZE(co_consts); + _Py_UOpsSymType **sym_consts = ctx->limit - co_const_len; + ctx->limit -= co_const_len; + if (ctx->limit <= ctx->n_consumed) { + return NULL; + } + for (Py_ssize_t i = 0; i < co_const_len; i++) { + _Py_UOpsSymType *res = sym_init_const(ctx, PyTuple_GET_ITEM(co_consts, i)); + if (res == NULL) { + return NULL; + } + sym_consts[i] = res; + } + + return sym_consts; +} + +static inline _Py_UOpsSymType* sym_init_unknown(_Py_UOpsAbstractInterpContext *ctx); + +// 0 on success, -1 on error. +static int +ctx_frame_push( + _Py_UOpsAbstractInterpContext *ctx, + PyCodeObject *co, + _Py_UOpsSymType **localsplus_start, + int n_locals_already_filled, + int curr_stackentries +) +{ + _Py_UOpsSymType **sym_consts = create_sym_consts(ctx, co->co_consts); + if (sym_consts == NULL) { + return -1; + } + assert(ctx->curr_frame_depth < MAX_ABSTRACT_FRAME_DEPTH); + _Py_UOpsAbstractFrame *frame = &ctx->frames[ctx->curr_frame_depth]; + ctx->curr_frame_depth++; + + frame->sym_consts = sym_consts; + frame->sym_consts_len = (int)Py_SIZE(co->co_consts); + frame->stack_len = co->co_stacksize; + frame->locals_len = co->co_nlocalsplus; + + frame->locals = localsplus_start; + frame->stack = frame->locals + co->co_nlocalsplus; + frame->stack_pointer = frame->stack + curr_stackentries; + ctx->n_consumed = localsplus_start + (co->co_nlocalsplus + co->co_stacksize); + if (ctx->n_consumed >= ctx->limit) { + return -1; + } + + + // Initialize with the initial state of all local variables + for (int i = n_locals_already_filled; i < co->co_nlocalsplus; i++) { + _Py_UOpsSymType *local = sym_init_unknown(ctx); + if (local == NULL) { + return -1; + } + frame->locals[i] = local; + } + + + // Initialize the stack as well + for (int i = 0; i < curr_stackentries; i++) { + _Py_UOpsSymType *stackvar = sym_init_unknown(ctx); + if (stackvar == NULL) { + return -1; + } + frame->stack[i] = stackvar; + } + + ctx->frame = frame; + return 0; +} + +static void +abstractcontext_fini(_Py_UOpsAbstractInterpContext *ctx) +{ + if (ctx == NULL) { + return; + } + ctx->curr_frame_depth = 0; + int tys = ctx->t_arena.ty_curr_number; + for (int i = 0; i < tys; i++) { + Py_CLEAR(ctx->t_arena.arena[i].const_val); + } +} + +static int +abstractcontext_init( + _Py_UOpsAbstractInterpContext *ctx, + PyCodeObject *co, + int curr_stacklen, + int ir_entries, + _PyUOpInstruction *new_writebuffer +) +{ + ctx->limit = ctx->locals_and_stack + MAX_ABSTRACT_INTERP_SIZE; + ctx->n_consumed = ctx->locals_and_stack; +#ifdef Py_DEBUG // Aids debugging a little. There should never be NULL in the abstract interpreter. + for (int i = 0 ; i < MAX_ABSTRACT_INTERP_SIZE; i++) { + ctx->locals_and_stack[i] = NULL; + } +#endif + + // Setup the arena for sym expressions. + ctx->t_arena.ty_curr_number = 0; + ctx->t_arena.ty_max_number = TY_ARENA_SIZE; + + // Frame setup + ctx->curr_frame_depth = 0; + if (ctx_frame_push(ctx, co, ctx->n_consumed, 0, curr_stacklen) < 0) { + return -1; + } + + // IR and sym setup + ctx->frequent_syms.push_nulL_sym = NULL; + + // Emitter setup + ctx->emitter.writebuffer = new_writebuffer; + ctx->emitter.curr_i = 0; + ctx->emitter.writebuffer_end = new_writebuffer + ir_entries; + return 0; +} + + +static inline bool +sym_is_type(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ); +static inline uint64_t +sym_type_get_refinement(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ); + +static inline PyFunctionObject * +extract_func_from_sym(_Py_UOpsSymType *callable_sym) +{ + assert(callable_sym != NULL); + if (!sym_is_type(callable_sym, PYFUNCTION_TYPE_VERSION_TYPE)) { + DPRINTF(1, "error: _PUSH_FRAME not function type\n"); + return NULL; + } + uint64_t func_version = sym_type_get_refinement(callable_sym, PYFUNCTION_TYPE_VERSION_TYPE); + PyFunctionObject *func = _PyFunction_LookupByVersion((uint32_t)func_version); + if (func == NULL) { + OPT_STAT_INC(optimizer_failure_reason_null_function); + DPRINTF(1, "error: _PUSH_FRAME cannot find func version\n"); + return NULL; + } + return func; +} + + +static int +ctx_frame_pop( + _Py_UOpsAbstractInterpContext *ctx +) +{ + _Py_UOpsAbstractFrame *frame = ctx->frame; + + ctx->n_consumed = frame->locals; + ctx->curr_frame_depth--; + assert(ctx->curr_frame_depth >= 1); + ctx->frame = &ctx->frames[ctx->curr_frame_depth - 1]; + + ctx->limit += frame->sym_consts_len; + return 0; +} + +static void +sym_set_type_from_const(_Py_UOpsSymType *sym, PyObject *obj); + +// Steals a reference to const_val +static _Py_UOpsSymType* +_Py_UOpsSymType_New(_Py_UOpsAbstractInterpContext *ctx, + PyObject *const_val) +{ + _Py_UOpsSymType *self = &ctx->t_arena.arena[ctx->t_arena.ty_curr_number]; + if (ctx->t_arena.ty_curr_number >= ctx->t_arena.ty_max_number) { + OPT_STAT_INC(optimizer_failure_reason_no_memory); + DPRINTF(1, "out of space for symbolic expression type\n"); + return NULL; + } + ctx->t_arena.ty_curr_number++; + self->const_val = NULL; + self->types = 0; + + if (const_val != NULL) { + self->const_val = Py_NewRef(const_val); + } + + return self; +} + + +static void +sym_set_type(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ, uint64_t refinement) +{ + sym->types |= 1 << typ; + if (typ <= MAX_TYPE_WITH_REFINEMENT) { + sym->refinement[typ] = refinement; + } +} + +// We need to clear the type information on every escaping/impure instruction. +// Consider the following code +/* +foo.attr +bar() # opaque call +foo.attr +*/ +// We can't propagate the type information of foo.attr over across bar +// (at least, not without re-installing guards). `bar()` may call random code +// that invalidates foo's type version tag. +static void +sym_copy_immutable_type_info(_Py_UOpsSymType *from_sym, _Py_UOpsSymType *to_sym) +{ + to_sym->types = (from_sym->types & IMMUTABLES); + if (to_sym->types) { + Py_XSETREF(to_sym->const_val, Py_XNewRef(from_sym->const_val)); + } +} + +static void +sym_set_type_from_const(_Py_UOpsSymType *sym, PyObject *obj) +{ + PyTypeObject *tp = Py_TYPE(obj); + + if (tp->tp_version_tag != 0) { + sym_set_type(sym, GUARD_TYPE_VERSION_TYPE, tp->tp_version_tag); + } + if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) { + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(obj); + if(_PyDictOrValues_IsValues(dorv)) { + sym_set_type(sym, GUARD_DORV_VALUES_TYPE, 0); + } + } + if (tp == &PyLong_Type) { + sym_set_type(sym, PYLONG_TYPE, 0); + } + else if (tp == &PyFloat_Type) { + sym_set_type(sym, PYFLOAT_TYPE, 0); + } + else if (tp == &PyUnicode_Type) { + sym_set_type(sym, PYUNICODE_TYPE, 0); + } + else if (tp == &PyFunction_Type) { + sym_set_type(sym, PYFUNCTION_TYPE_VERSION_TYPE, + ((PyFunctionObject *)(obj))->func_version); + } + +} + + +static inline _Py_UOpsSymType* +sym_init_unknown(_Py_UOpsAbstractInterpContext *ctx) +{ + return _Py_UOpsSymType_New(ctx,NULL); +} + +// Takes a borrowed reference to const_val. +static inline _Py_UOpsSymType* +sym_init_const(_Py_UOpsAbstractInterpContext *ctx, PyObject *const_val) +{ + assert(const_val != NULL); + _Py_UOpsSymType *temp = _Py_UOpsSymType_New( + ctx, + const_val + ); + if (temp == NULL) { + return NULL; + } + sym_set_type_from_const(temp, const_val); + sym_set_type(temp, TRUE_CONST, 0); + return temp; +} + +static _Py_UOpsSymType* +sym_init_push_null(_Py_UOpsAbstractInterpContext *ctx) +{ + if (ctx->frequent_syms.push_nulL_sym != NULL) { + return ctx->frequent_syms.push_nulL_sym; + } + _Py_UOpsSymType *null_sym = sym_init_unknown(ctx); + if (null_sym == NULL) { + return NULL; + } + sym_set_type(null_sym, NULL_TYPE, 0); + ctx->frequent_syms.push_nulL_sym = null_sym; + return null_sym; +} + +static inline bool +sym_is_type(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ) +{ + if ((sym->types & (1 << typ)) == 0) { + return false; + } + return true; +} + +static inline bool +sym_matches_type(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ, uint64_t refinement) +{ + if (!sym_is_type(sym, typ)) { + return false; + } + if (typ <= MAX_TYPE_WITH_REFINEMENT) { + return sym->refinement[typ] == refinement; + } + return true; +} + +static uint64_t +sym_type_get_refinement(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ) +{ + assert(sym_is_type(sym, typ)); + assert(typ <= MAX_TYPE_WITH_REFINEMENT); + return sym->refinement[typ]; +} + + +static inline bool +op_is_end(uint32_t opcode) +{ + return opcode == _EXIT_TRACE || opcode == _JUMP_TO_TOP || + opcode == _JUMP_ABSOLUTE; +} + + +static inline bool +op_is_bookkeeping(uint32_t opcode) { + return (opcode == _SET_IP || + opcode == _CHECK_VALIDITY || + opcode == _SAVE_RETURN_OFFSET || + opcode == _RESUME_CHECK); +} + + +static inline bool +is_const(_Py_UOpsSymType *expr) +{ + return expr->const_val != NULL; +} + +static inline PyObject * +get_const_borrow(_Py_UOpsSymType *expr) +{ + return expr->const_val; +} + +static inline PyObject * +get_const(_Py_UOpsSymType *expr) +{ + return Py_NewRef(expr->const_val); +} + + +static int +clear_locals_type_info(_Py_UOpsAbstractInterpContext *ctx) { + int locals_entries = ctx->frame->locals_len; + for (int i = 0; i < locals_entries; i++) { + _Py_UOpsSymType *new_local = sym_init_unknown(ctx); + if (new_local == NULL) { + return -1; + } + sym_copy_immutable_type_info(ctx->frame->locals[i], new_local); + ctx->frame->locals[i] = new_local; + } + return 0; +} + +static inline int +emit_i(uops_emitter *emitter, + _PyUOpInstruction inst) +{ + if (emitter->writebuffer + emitter->curr_i >= emitter->writebuffer_end) { + OPT_STAT_INC(optimizer_failure_reason_no_writebuffer); + DPRINTF(1, "out of emission space\n"); + return -1; + } + if (inst.opcode == _NOP) { + return 0; + } + DPRINTF(2, "Emitting instruction at [%d] op: %s, oparg: %d, target: %d, operand: %" PRIu64 " \n", + emitter->curr_i, + _PyOpcode_uop_name[inst.opcode], + inst.oparg, + inst.target, + inst.operand); + emitter->writebuffer[emitter->curr_i] = inst; + emitter->curr_i++; + return 0; +} + +static inline bool +op_is_zappable(int opcode) +{ + switch(opcode) { + case _SET_IP: + case _CHECK_VALIDITY: + return true; + default: + return (_PyUop_Flags[opcode] & HAS_PURE_FLAG) && !((_PyUop_Flags[opcode] & HAS_DEOPT_FLAG)); + } +} + + +static inline int +emit_const(uops_emitter *emitter, + PyObject *const_val, + int num_pops) +{ + _PyUOpInstruction shrink_stack = {_SHRINK_STACK, num_pops, 0, 0}; + // If all that precedes a _SHRINK_STACK is a bunch of pure instructions, + // then we can safely eliminate that without side effects + int net_stack_effect = -num_pops; + _PyUOpInstruction *back = emitter->writebuffer + emitter->curr_i - 1; + while (back >= emitter->writebuffer && + op_is_zappable(back->opcode)) { + net_stack_effect += _PyUop_NetStackEffect(back->opcode, back->oparg); + back--; + if (net_stack_effect == 0) { + break; + } + } + if (net_stack_effect == 0) { + back = emitter->writebuffer + emitter->curr_i - 1; + net_stack_effect = -num_pops; + // Back up over the previous loads and zap them. + while(net_stack_effect != 0) { + net_stack_effect += _PyUop_NetStackEffect(back->opcode, back->oparg); + if (back->opcode == _LOAD_CONST_INLINE || + back->opcode == _LOAD_CONST_INLINE_WITH_NULL) { + PyObject *old_const_val = (PyObject *)back->operand; + Py_DECREF(old_const_val); + back->operand = (uintptr_t)NULL; + } + back->opcode = NOP; + back--; + } + } + else { + if (emit_i(emitter, shrink_stack) < 0) { + return -1; + } + } + int load_const_opcode = _Py_IsImmortal(const_val) + ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE; + if (load_const_opcode == _LOAD_CONST_INLINE) { + Py_INCREF(const_val); + } + _PyUOpInstruction load_const = {load_const_opcode, 0, 0, (uintptr_t)const_val}; + if (emit_i(emitter, load_const) < 0) { + return -1; + } + + return 0; +} + + +#define DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dval, result) \ +do { \ + { \ + result = PyFloat_FromDouble(dval); \ + if ((result) == NULL) goto error; \ + } \ +} while (0) + +#define DEOPT_IF(COND, INSTNAME) \ + if ((COND)) { \ + goto guard_required; \ + } + +#ifndef Py_DEBUG +#define GETITEM(ctx, i) (ctx->frame->sym_consts[(i)]) +#else +static inline _Py_UOpsSymType * +GETITEM(_Py_UOpsAbstractInterpContext *ctx, Py_ssize_t i) { + assert(i < ctx->frame->sym_consts_len); + return ctx->frame->sym_consts[i]; +} +#endif + +static int +uop_abstract_interpret_single_inst( + _PyUOpInstruction *inst, + _PyUOpInstruction *end, + _Py_UOpsAbstractInterpContext *ctx +) +{ +#define STACK_LEVEL() ((int)(stack_pointer - ctx->frame->stack)) +#define STACK_SIZE() (ctx->frame->stack_len) +#define BASIC_STACKADJ(n) (stack_pointer += n) + +#ifdef Py_DEBUG + #define STACK_GROW(n) do { \ + assert(n >= 0); \ + BASIC_STACKADJ(n); \ + if (STACK_LEVEL() > STACK_SIZE()) { \ + DPRINTF(2, "err: %d, %d\n", STACK_SIZE(), STACK_LEVEL())\ + } \ + assert(STACK_LEVEL() <= STACK_SIZE()); \ + } while (0) + #define STACK_SHRINK(n) do { \ + assert(n >= 0); \ + assert(STACK_LEVEL() >= n); \ + BASIC_STACKADJ(-(n)); \ + } while (0) +#else + #define STACK_GROW(n) BASIC_STACKADJ(n) + #define STACK_SHRINK(n) BASIC_STACKADJ(-(n)) +#endif +#define PEEK(idx) (((stack_pointer)[-(idx)])) +#define GETLOCAL(idx) ((ctx->frame->locals[idx])) + +#define CURRENT_OPARG() (oparg) + +#define CURRENT_OPERAND() (operand) + +#define TIER_TWO_ONLY ((void)0) + + int oparg = inst->oparg; + uint32_t opcode = inst->opcode; + uint64_t operand = inst->operand; + + _Py_UOpsSymType **stack_pointer = ctx->frame->stack_pointer; + _PyUOpInstruction new_inst = *inst; + + DPRINTF(3, "Abstract interpreting %s:%d ", + _PyOpcode_uop_name[opcode], + oparg); + switch (opcode) { +#include "abstract_interp_cases.c.h" + // Note: LOAD_FAST_CHECK is not pure!!! + case LOAD_FAST_CHECK: { + STACK_GROW(1); + _Py_UOpsSymType *local = GETLOCAL(oparg); + // We guarantee this will error - just bail and don't optimize it. + if (sym_is_type(local, NULL_TYPE)) { + goto error; + } + PEEK(1) = local; + break; + } + case LOAD_FAST: { + STACK_GROW(1); + _Py_UOpsSymType * local = GETLOCAL(oparg); + if (sym_is_type(local, NULL_TYPE)) { + Py_UNREACHABLE(); + } + // Guaranteed by the CPython bytecode compiler to not be uninitialized. + PEEK(1) = GETLOCAL(oparg); + assert(PEEK(1)); + + break; + } + case LOAD_FAST_AND_CLEAR: { + STACK_GROW(1); + PEEK(1) = GETLOCAL(oparg); + break; + } + case LOAD_CONST: { + STACK_GROW(1); + PEEK(1) = (_Py_UOpsSymType *)GETITEM( + ctx, oparg); + assert(is_const(PEEK(1))); + // Peephole: inline constants. + PyObject *val = get_const_borrow(PEEK(1)); + new_inst.opcode = _Py_IsImmortal(val) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE; + if (new_inst.opcode == _LOAD_CONST_INLINE) { + Py_INCREF(val); + } + new_inst.operand = (uintptr_t)val; + break; + } + case _LOAD_CONST_INLINE: + case _LOAD_CONST_INLINE_BORROW: + { + _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); + if (sym_const == NULL) { + goto error; + } + // We need to incref it for it to safely decref in the + // executor finalizer. + if (opcode == _LOAD_CONST_INLINE) { + Py_INCREF(inst->operand); + } + STACK_GROW(1); + PEEK(1) = sym_const; + assert(is_const(PEEK(1))); + break; + } + case _LOAD_CONST_INLINE_WITH_NULL: + case _LOAD_CONST_INLINE_BORROW_WITH_NULL: + { + _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); + if (sym_const == NULL) { + goto error; + } + // We need to incref it for it to safely decref in the + // executor finalizer. + if (opcode == _LOAD_CONST_INLINE_WITH_NULL) { + Py_INCREF(inst->operand); + } + STACK_GROW(1); + PEEK(1) = sym_const; + assert(is_const(PEEK(1))); + _Py_UOpsSymType *null_sym = sym_init_push_null(ctx); + if (null_sym == NULL) { + goto error; + } + STACK_GROW(1); + PEEK(1) = null_sym; + break; + } + case STORE_FAST_MAYBE_NULL: + case STORE_FAST: { + _Py_UOpsSymType *value = PEEK(1); + GETLOCAL(oparg) = value; + STACK_SHRINK(1); + break; + } + case COPY: { + _Py_UOpsSymType *bottom = PEEK(1 + (oparg - 1)); + STACK_GROW(1); + PEEK(1) = bottom; + break; + } + + case PUSH_NULL: { + STACK_GROW(1); + _Py_UOpsSymType *null_sym = sym_init_push_null(ctx); + if (null_sym == NULL) { + goto error; + } + PEEK(1) = null_sym; + break; + } + + case _INIT_CALL_PY_EXACT_ARGS: { + // Don't put in the new frame. Leave it be so that _PUSH_FRAME + // can extract callable, self_or_null and args later. + // This also means our stack pointer diverges from the real VM. + + // IMPORTANT: make sure there is no interference + // between this and _PUSH_FRAME. That is a required invariant. + break; + } + + case _PUSH_FRAME: { + // From _INIT_CALL_PY_EXACT_ARGS + + int argcount = oparg; + // _INIT_CALL_PY_EXACT_ARGS's real stack effect in the VM. + stack_pointer += -1 - oparg; + // TOS is the new callable, above it self_or_null and args + + PyFunctionObject *func = extract_func_from_sym(PEEK(1)); + if (func == NULL) { + goto error; + } + PyCodeObject *co = (PyCodeObject *)func->func_code; + + _Py_UOpsSymType *self_or_null = PEEK(0); + assert(self_or_null != NULL); + _Py_UOpsSymType **args = &PEEK(-1); + assert(args != NULL); + if (!sym_is_type(self_or_null, NULL_TYPE) && + !sym_is_type(self_or_null, SELF_OR_NULL)) { + // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in + // VM + args--; + argcount++; + } + // This is _PUSH_FRAME's stack effect + STACK_SHRINK(1); + ctx->frame->stack_pointer = stack_pointer; + _Py_UOpsSymType **localsplus_start = ctx->n_consumed; + int n_locals_already_filled = 0; + // Can determine statically, so we interleave the new locals + // and make the current stack the new locals. + // This also sets up for true call inlining. + if (!sym_is_type(self_or_null, SELF_OR_NULL)) { + localsplus_start = args; + n_locals_already_filled = argcount; + } + if (ctx_frame_push(ctx, co, localsplus_start, n_locals_already_filled, 0) != 0){ + goto error; + } + stack_pointer = ctx->frame->stack_pointer; + break; + } + + case _POP_FRAME: { + assert(STACK_LEVEL() == 1); + _Py_UOpsSymType *retval = PEEK(1); + STACK_SHRINK(1); + ctx->frame->stack_pointer = stack_pointer; + + if (ctx_frame_pop(ctx) != 0){ + goto error; + } + stack_pointer = ctx->frame->stack_pointer; + // Push retval into new frame. + STACK_GROW(1); + PEEK(1) = retval; + break; + } + + case _CHECK_PEP_523: + /* Setting the eval frame function invalidates + * all executors, so no need to check dynamically */ + if (_PyInterpreterState_GET()->eval_frame == NULL) { + new_inst.opcode = _NOP; + } + break; + case _CHECK_GLOBALS: + case _CHECK_BUILTINS: + case _SET_IP: + case _CHECK_VALIDITY: + case _SAVE_RETURN_OFFSET: + break; + default: + DPRINTF(1, "Unknown opcode in abstract interpreter\n"); + Py_UNREACHABLE(); + } + assert(ctx->frame != NULL); + DPRINTF(3, " stack_level %d\n", STACK_LEVEL()); + ctx->frame->stack_pointer = stack_pointer; + assert(STACK_LEVEL() >= 0); + + if (emit_i(&ctx->emitter, new_inst) < 0) { + return -1; + } + + return 0; + +pop_2_error_tier_two: + STACK_SHRINK(1); + STACK_SHRINK(1); +error: + DPRINTF(1, "Encountered error in abstract interpreter\n"); + return -1; + +} + + static int get_mutations(PyObject* dict) { @@ -206,57 +1100,126 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, builtins = func->func_builtins; break; } - case _JUMP_TO_TOP: - case _EXIT_TRACE: - return 1; + default: + if (op_is_end(opcode)) { + return 1; + } + break; } } return 0; } -static void -peephole_opt(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, int buffer_size) +static int +uop_abstract_interpret( + PyCodeObject *co, + _PyUOpInstruction *trace, + _PyUOpInstruction *new_trace, + int trace_len, + int curr_stacklen +) { - PyCodeObject *co = (PyCodeObject *)frame->f_executable; - for (int pc = 0; pc < buffer_size; pc++) { - int opcode = buffer[pc].opcode; - switch(opcode) { - case _LOAD_CONST: { - assert(co != NULL); - PyObject *val = PyTuple_GET_ITEM(co->co_consts, buffer[pc].oparg); - buffer[pc].opcode = _Py_IsImmortal(val) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE; - buffer[pc].operand = (uintptr_t)val; - break; - } - case _CHECK_PEP_523: - { - /* Setting the eval frame function invalidates - * all executors, so no need to check dynamically */ - if (_PyInterpreterState_GET()->eval_frame == NULL) { - buffer[pc].opcode = _NOP; + bool did_loop_peel = false; + + _Py_UOpsAbstractInterpContext ctx; + + if (abstractcontext_init( + &ctx, + co, curr_stacklen, + trace_len, new_trace) < 0) { + goto error; + } + _PyUOpInstruction *curr = NULL; + _PyUOpInstruction *end = NULL; + int status = 0; + bool needs_clear_locals = true; + bool has_enough_space_to_duplicate_loop = true; + int res = 0; + +loop_peeling: + curr = trace; + end = trace + trace_len; + needs_clear_locals = true; + ; + while (curr < end && !op_is_end(curr->opcode)) { + + if (!(_PyUop_Flags[curr->opcode] & HAS_PURE_FLAG) && + !(_PyUop_Flags[curr->opcode] & HAS_SPECIAL_OPT_FLAG) && + !op_is_bookkeeping(curr->opcode) && + !(_PyUop_Flags[curr->opcode] & HAS_GUARD_FLAG)) { + DPRINTF(3, "Impure %s\n", _PyOpcode_uop_name[curr->opcode]); + if (needs_clear_locals) { + if (clear_locals_type_info(&ctx) < 0) { + goto error; } - break; } - case _PUSH_FRAME: - case _POP_FRAME: - { - PyFunctionObject *func = (PyFunctionObject *)buffer[pc].operand; - if (func == NULL) { - co = NULL; - } - else { - assert(PyFunction_Check(func)); - co = (PyCodeObject *)func->func_code; - } - break; + needs_clear_locals = false; + } + else { + needs_clear_locals = true; + } + + status = uop_abstract_interpret_single_inst( + curr, end, &ctx + ); + if (status == -1) { + goto error; + } + + curr++; + + } + + assert(op_is_end(curr->opcode)); + + // If we end in a loop, and we have a lot of space left, peel the loop for + // poor man's loop invariant code motion for guards + // https://en.wikipedia.org/wiki/Loop_splitting + has_enough_space_to_duplicate_loop = ((ctx.emitter.curr_i * 3) < + (int)(ctx.emitter.writebuffer_end - ctx.emitter.writebuffer)); + if (!did_loop_peel && curr->opcode == _JUMP_TO_TOP && has_enough_space_to_duplicate_loop) { + OPT_STAT_INC(loop_body_duplication_attempts); + did_loop_peel = true; + _PyUOpInstruction jump_header = {_JUMP_ABSOLUTE_HEADER, (ctx.emitter.curr_i), 0, 0}; + if (emit_i(&ctx.emitter, jump_header) < 0) { + goto error; + } + DPRINTF(1, "loop_peeling!\n"); + goto loop_peeling; + } + else { +#if defined(Py_STATS) || defined(Py_DEBUG) + if(!did_loop_peel && curr->opcode == _JUMP_TO_TOP && !has_enough_space_to_duplicate_loop) { + OPT_STAT_INC(loop_body_duplication_no_mem); + DPRINTF(1, "no space for loop peeling\n"); + } +#endif + if (did_loop_peel) { + OPT_STAT_INC(loop_body_duplication_successes); + assert(curr->opcode == _JUMP_TO_TOP); + _PyUOpInstruction jump_abs = {_JUMP_ABSOLUTE, (ctx.emitter.curr_i), 0, 0}; + if (emit_i(&ctx.emitter, jump_abs) < 0) { + goto error; + } + } else { + if (emit_i(&ctx.emitter, *curr) < 0) { + goto error; } - case _JUMP_TO_TOP: - case _EXIT_TRACE: - return; } } + + + res = ctx.emitter.curr_i; + abstractcontext_fini(&ctx); + + return res; + +error: + abstractcontext_fini(&ctx); + return -1; } + static void remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size) { @@ -276,7 +1239,7 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size) buffer[pc].opcode = NOP; } } - else if (opcode == _JUMP_TO_TOP || opcode == _EXIT_TRACE) { + else if (op_is_end(opcode)) { break; } else { @@ -295,6 +1258,10 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size) } } + +// 0 - failure, no error raised, just fall back to Tier 1 +// -1 - failure, and raise error +// 1 - optimizer success int _Py_uop_analyze_and_optimize( _PyInterpreterFrame *frame, @@ -304,11 +1271,36 @@ _Py_uop_analyze_and_optimize( _PyBloomFilter *dependencies ) { + OPT_STAT_INC(optimizer_attempts); + _PyUOpInstruction temp_writebuffer[UOP_MAX_TRACE_WORKING_LENGTH]; + int err = remove_globals(frame, buffer, buffer_size, dependencies); if (err <= 0) { - return err; + goto error; } - peephole_opt(frame, buffer, buffer_size); - remove_unneeded_uops(buffer, buffer_size); + + // Pass: Abstract interpretation and symbolic analysis + int new_trace_len = uop_abstract_interpret( + (PyCodeObject *)frame->f_executable, buffer, temp_writebuffer, + buffer_size, curr_stacklen); + + if (new_trace_len < 0) { + goto error; + } + + + remove_unneeded_uops(temp_writebuffer, new_trace_len); + + // Fill in our new trace! + memcpy(buffer, temp_writebuffer, new_trace_len * sizeof(_PyUOpInstruction)); + + + OPT_STAT_INC(optimizer_successes); return 1; +error: + + // The only valid error we can raise is MemoryError. + // Other times it's not really errors but things like not being able + // to fetch a function version because the function got deleted. + return PyErr_Occurred() ? -1 : 0; } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 0cac7109340129..bf6bf66c243534 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1252,6 +1252,7 @@ init_interp_main(PyThreadState *tstate) if (_Py_get_xoption(&config->xoptions, L"uops") != NULL) { enabled = 1; } + enabled = 1; // TEMPORARY: always enable if (enabled) { #else // Always enable tier two for JIT builds (ignoring the environment diff --git a/Python/specialize.c b/Python/specialize.c index e38e3556a6d642..e288db90d01105 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -240,6 +240,21 @@ print_optimization_stats(FILE *out, OptimizationStats *stats) print_histogram(out, "Trace run length", stats->trace_run_length_hist); print_histogram(out, "Optimized trace length", stats->optimized_trace_length_hist); + fprintf(out, "Optimization optimizer attempts: %" PRIu64 "\n", stats->optimizer_attempts); + fprintf(out, "Optimization optimizer successes: %" PRIu64 "\n", stats->optimizer_successes); + fprintf(out, "Optimization optimizer failure null function: %" PRIu64 "\n", + stats->optimizer_failure_reason_null_function); + fprintf(out, "Optimization optimizer failure no memory: %" PRIu64 "\n", + stats->optimizer_failure_reason_no_memory); + fprintf(out, "Optimization optimizer failure no writebuffer left: %" PRIu64 "\n", + stats->optimizer_failure_reason_no_writebuffer); + fprintf(out, "Optimization optimizer loop duplication attempts: %" PRIu64 "\n", + stats->loop_body_duplication_attempts); + fprintf(out, "Optimization optimizer loop duplication successes: %" PRIu64 "\n", + stats->loop_body_duplication_successes); + fprintf(out, "Optimization optimizer loop duplication no memory: %" PRIu64 "\n", + stats->loop_body_duplication_no_mem); + const char* const* names; for (int i = 0; i < 512; i++) { if (i < 256) { diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index 444063d2148934..dffb0c46984c50 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -83,6 +83,7 @@ def clean_lines(text): Python/frozen_modules/*.h Python/generated_cases.c.h Python/executor_cases.c.h +Python/abstract_interp_cases.c.h # not actually source Python/bytecodes.c diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index c75aff8c1723c1..14bcd85b9eae59 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -734,6 +734,6 @@ Modules/expat/xmlrole.c - error - ## other Modules/_io/_iomodule.c - _PyIO_Module - Modules/_sqlite/module.c - _sqlite3module - -Python/optimizer_analysis.c - _Py_PartitionRootNode_Type - +Python/optimizer_analysis.c - _Py_UOpsAbstractFrame_Type - Python/optimizer_analysis.c - _Py_UOpsAbstractInterpContext_Type - Modules/clinic/md5module.c.h _md5_md5 _keywords - diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index b80fa66e2a159a..7faa415232cdef 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -3,6 +3,7 @@ import parser from typing import Optional +from tier2_abstract_common import SPECIALLY_HANDLED_ABSTRACT_INSTR, SPECIAL_GUARDS @dataclass class Properties: @@ -25,6 +26,7 @@ class Properties: pure: bool passthrough: bool guard: bool + specially_handled_in_optimizer: bool def dump(self, indent: str) -> None: print(indent, end="") @@ -52,6 +54,7 @@ def from_list(properties: list["Properties"]) -> "Properties": pure=all(p.pure for p in properties), passthrough=all(p.passthrough for p in properties), guard=all(p.guard for p in properties), + specially_handled_in_optimizer=False, ) @@ -74,6 +77,7 @@ def from_list(properties: list["Properties"]) -> "Properties": pure=False, passthrough=False, guard=False, + specially_handled_in_optimizer=False, ) @@ -473,7 +477,8 @@ def compute_properties(op: parser.InstDef) -> Properties: has_free=has_free, pure="pure" in op.annotations, passthrough=passthrough, - guard=passthrough and deopts, + guard=op.name in SPECIAL_GUARDS or (passthrough and deopts and infallible), + specially_handled_in_optimizer=op.name in SPECIALLY_HANDLED_ABSTRACT_INSTR, ) diff --git a/Tools/cases_generator/generators_common.py b/Tools/cases_generator/generators_common.py index 2fc2ab115321cf..0e804859668d27 100644 --- a/Tools/cases_generator/generators_common.py +++ b/Tools/cases_generator/generators_common.py @@ -211,8 +211,10 @@ def cflags(p: Properties) -> str: flags.append("HAS_ESCAPES_FLAG") if p.pure: flags.append("HAS_PURE_FLAG") - if p.passthrough: - flags.append("HAS_PASSTHROUGH_FLAG") + if p.guard: + flags.append("HAS_GUARD_FLAG") + if p.specially_handled_in_optimizer: + flags.append("HAS_SPECIAL_OPT_FLAG") if flags: return " | ".join(flags) else: diff --git a/Tools/cases_generator/interpreter_definition.md b/Tools/cases_generator/interpreter_definition.md index e87aff43762b11..a68d42690791e2 100644 --- a/Tools/cases_generator/interpreter_definition.md +++ b/Tools/cases_generator/interpreter_definition.md @@ -156,12 +156,11 @@ and their refinements are below. They obey the following predicates: * `NULL_TYPE`: `val == NULL` * `GUARD_TYPE_VERSION_TYPE`: `type->tp_version_tag == auxillary` * `GUARD_DORV_VALUES_TYPE`: `_PyDictOrValues_IsValues(obj)` -* `GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_TYPE`: - `_PyDictOrValues_IsValues(obj) || _PyObject_MakeInstanceAttributesFromDict(obj, dorv)` * `GUARD_KEYS_VERSION_TYPE`: `owner_heap_type->ht_cached_keys->dk_version == auxillary` * `PYMETHOD_TYPE`: `Py_TYPE(val) == &PyMethod_Type` * `PYFUNCTION_TYPE_VERSION_TYPE`: `PyFunction_Check(callable) && func->func_version == auxillary && code->co_argcount == oparg + (self_or_null != NULL)` +* `SELF_OR_NULL`: `val == NULL || val != NULL` An `inst` without `stack_effect` is a transitional form to allow the original C code diff --git a/Tools/cases_generator/opcode_metadata_generator.py b/Tools/cases_generator/opcode_metadata_generator.py index 3e9fa3e26daa53..b2f797fb553d85 100644 --- a/Tools/cases_generator/opcode_metadata_generator.py +++ b/Tools/cases_generator/opcode_metadata_generator.py @@ -51,7 +51,8 @@ "ERROR", "ESCAPES", "PURE", - "PASSTHROUGH", + "GUARD", + "SPECIAL_OPT", ] diff --git a/Tools/cases_generator/stack.py b/Tools/cases_generator/stack.py index f62ece43c1be7f..28ad9507b8e0bb 100644 --- a/Tools/cases_generator/stack.py +++ b/Tools/cases_generator/stack.py @@ -3,7 +3,7 @@ from dataclasses import dataclass from cwriter import CWriter -UNUSED = {"unused"} +UNUSED = {"unused", "__unused_"} def maybe_parenthesize(sym: str) -> str: @@ -168,11 +168,11 @@ def push(self, var: StackItem) -> str: self.top_offset.push(var) return "" - def flush(self, out: CWriter) -> None: + def flush(self, out: CWriter, cast_type: str = "PyObject *") -> None: out.start_line() for var in self.variables: if not var.peek: - cast = "(PyObject *)" if var.type else "" + cast = f"({cast_type})" if var.type else "" if var.name not in UNUSED and not var.is_array(): if var.condition: out.emit(f"if ({var.condition}) ") diff --git a/Tools/cases_generator/tier2_abstract_common.py b/Tools/cases_generator/tier2_abstract_common.py new file mode 100644 index 00000000000000..92e896565c43d2 --- /dev/null +++ b/Tools/cases_generator/tier2_abstract_common.py @@ -0,0 +1,34 @@ +# We have to keep this here instead of tier2_abstract_generator.py +# to avoid a circular import. +SPECIALLY_HANDLED_ABSTRACT_INSTR = { + "LOAD_FAST", + "LOAD_FAST_CHECK", + "LOAD_FAST_AND_CLEAR", + "LOAD_CONST", + "STORE_FAST", + "STORE_FAST_MAYBE_NULL", + "COPY", + "PUSH_NULL", + # Frame stuff + "_PUSH_FRAME", + "_POP_FRAME", + "_INIT_CALL_PY_EXACT_ARGS", + # Bookkeeping + "_SET_IP", + "_CHECK_VALIDITY", + "_SAVE_RETURN_OFFSET", + "_CHECK_PEP_523", + "_CHECK_GLOBALS", + "_CHECK_BUILTINS", + # Custom tier 2 things + "_LOAD_CONST_INLINE", + "_LOAD_CONST_INLINE_WITH_NULL", + "_LOAD_CONST_INLINE_BORROW", + "_LOAD_CONST_INLINE_BORROW_WITH_NULL", +} + +SPECIAL_GUARDS = { + "_CHECK_PEP_523", + "_CHECK_GLOBALS", + "_CHECK_BUILTINS", +} diff --git a/Tools/cases_generator/tier2_abstract_generator.py b/Tools/cases_generator/tier2_abstract_generator.py new file mode 100644 index 00000000000000..73418c4269906b --- /dev/null +++ b/Tools/cases_generator/tier2_abstract_generator.py @@ -0,0 +1,435 @@ +"""Generate the cases for the tier 2 abstract interpreter. +Reads the instruction definitions from bytecodes.c. +Writes the cases to abstract_interp_cases.c.h, which is #included in optimizer_analysis.c +""" + +import argparse +import os.path +import sys +import dataclasses + +from analyzer import ( + Analysis, + Instruction, + Uop, + Part, + analyze_files, + Skip, + StackItem, + analysis_error, +) +from generators_common import ( + DEFAULT_INPUT, + ROOT, + write_header, + emit_tokens, + emit_to, + REPLACEMENT_FUNCTIONS, +) +from tier2_abstract_common import SPECIALLY_HANDLED_ABSTRACT_INSTR +from tier2_generator import tier2_replace_error +from cwriter import CWriter +from typing import TextIO, Iterator +from lexer import Token +from stack import StackOffset, Stack, SizeMismatch, UNUSED + +DEFAULT_OUTPUT = ROOT / "Python/abstract_interp_cases.c.h" + + +NO_CONST_OR_TYPE_EVALUATE = { + "_RESUME_CHECK", + "_GUARD_GLOBALS_VERSION", + "_GUARD_BUILTINS_VERSION", + "_CHECK_MANAGED_OBJECT_HAS_VALUES", + "_CHECK_PEP_523", + "_CHECK_STACK_SPACE", + "_INIT_CALL_PY_EXACT_ARGS", + "_END_SEND", + "_POP_TOP", + "_NOP", + "_SWAP", +} + + +MANGLED_NULL = "__null_" + +def declare_variables( + uop: Uop, + out: CWriter, + default_type: str = "_Py_UOpsSymType *", + skip_inputs: bool = False, + skip_peeks: bool = False, +) -> None: + # Don't declare anything for these guards, they will always be evaluated. + if uop.properties.guard and uop.name in NO_CONST_OR_TYPE_EVALUATE: + return + variables = set(UNUSED) + if not skip_inputs: + for var in reversed(uop.stack.inputs): + if skip_peeks and var.peek: + continue + if var.name not in variables: + type = default_type + if var.size != "1" and var.type == "PyObject **": + type = "_Py_UOpsSymType **" + variables.add(var.name) + if var.condition: + out.emit(f"{type}{var.name} = NULL;\n") + else: + out.emit(f"{type}{var.name};\n") + if var.name == MANGLED_NULL and not var.peek: + out.emit(f"{var.name} = sym_init_push_null(ctx);\n") + out.emit(f"if ({var.name} == NULL) {{ goto error; }}\n") + for var in uop.stack.outputs: + if skip_peeks and var.peek: + continue + if var.size != "1": + continue + if var.name not in variables: + variables.add(var.name) + type = default_type + if var.size != "1" and var.type == "PyObject **": + type = "_Py_UOpsSymType **" + if var.condition: + out.emit(f"{type}{var.name} = NULL;\n") + else: + out.emit(f"{type}{var.name};\n") + if var.name == MANGLED_NULL and not var.peek: + out.emit(f"{var.name} = sym_init_push_null(ctx);\n") + out.emit(f"if ({var.name} == NULL) {{ goto error; }}\n") + + +def tier2_replace_deopt( + out: CWriter, + tkn: Token, + tkn_iter: Iterator[Token], + uop: Uop, + unused: Stack, + inst: Instruction | None, +) -> None: + out.emit_at("if ", tkn) + out.emit(next(tkn_iter)) + emit_to(out, tkn_iter, "RPAREN") + next(tkn_iter) # Semi colon + out.emit(") goto error;\n") + + +TIER2_REPLACEMENT_FUNCTIONS = REPLACEMENT_FUNCTIONS.copy() +TIER2_REPLACEMENT_FUNCTIONS["ERROR_IF"] = tier2_replace_error +TIER2_REPLACEMENT_FUNCTIONS["DEOPT_IF"] = tier2_replace_deopt + +def _write_body_abstract_interp_impure_uop( + mangled_uop: Uop, uop: Uop, out: CWriter, stack: Stack +) -> None: + # Simply make all outputs effects unknown + + for var in mangled_uop.stack.outputs: + if (var.name in UNUSED and var.size == "1") or var.peek: + continue + + if var.size == "1": + if var.name != MANGLED_NULL: + out.emit(f"{var.name} = sym_init_unknown(ctx);\n") + out.emit(f"if({var.name} == NULL) goto error;\n") + if var.type_prop: + out.emit(f"sym_set_type({var.name}, {var.type_prop[0]}, 0);\n") + else: + # See UNPACK_SEQUENCE for when we need this. + out.emit( + f"for (int case_gen_i = 0; case_gen_i < ({var.size}); case_gen_i++) {{\n" + ) + out.emit(f"*(stack_pointer + case_gen_i) = sym_init_unknown(ctx);\n") + out.emit(f"if(*(stack_pointer + case_gen_i) == NULL) goto error;\n") + if var.type_prop: + out.emit( + f"sym_set_type(*(stack_pointer + case_gen_i), {var.type_prop[0]}, 0);\n" + ) + out.emit("}\n") + + +def mangle_uop_names(uop: Uop) -> Uop: + uop = dataclasses.replace(uop) + new_stack = dataclasses.replace(uop.stack) + new_stack.inputs = [ + dataclasses.replace(var, name=f"__{var.name}_") for var in uop.stack.inputs + ] + new_stack.outputs = [ + dataclasses.replace(var, name=f"__{var.name}_") for var in uop.stack.outputs + ] + uop.stack = new_stack + return uop + + +# Returns a tuple of a pointer to an array of subexpressions, the length of said array +# and a string containing the join of all other subexpressions obtained from stack input. +# This grabs variadic inputs that depend on things like oparg or cache +def get_subexpressions( + input_vars: list[StackItem], +) -> tuple[str | None, int | str, str]: + arr_var = [(var.name, var) for var in input_vars if var.size > "1"] + assert len(arr_var) <= 1, "Can have at most one array input from oparg/cache" + arr_var_name = arr_var[0][0] if len(arr_var) == 1 else None + arr_var_size = (arr_var[0][1].size or 0) if arr_var_name is not None else 0 + if arr_var_name is not None: + input_vars.remove(arr_var[0][1]) + var = ", ".join([v.name for v in input_vars]) + if var: + var = ", " + var + return arr_var_name, arr_var_size, var + + +def new_sym( + constant: str | None, +) -> str: + return ( + f"_Py_UOpsSymType_New(" + f"ctx, {constant or 'NULL'});" + ) + + +def declare_caches(uop: Uop, out: CWriter) -> None: + for cache in uop.caches: + if cache.name not in UNUSED: + if cache.size == 4: + type = cast = "PyObject *" + else: + type = f"uint{cache.size*16}_t " + cast = f"uint{cache.size*16}_t" + out.emit(f"{type}{cache.name} = ({cast})CURRENT_OPERAND();\n") + + +def _write_body_abstract_interp_pure_uop( + mangled_uop: Uop, uop: Uop, out: CWriter, stack: Stack +) -> None: + arr_var_name, arr_var_size, subexpressions = get_subexpressions( + mangled_uop.stack.inputs + ) + + # uop is non-trivial - we cannot const evaluate it + if uop.name in NO_CONST_OR_TYPE_EVALUATE: + for in_ in mangled_uop.stack.inputs: + out.emit(f"(void){in_.name};\n") + return + + # Constant prop handled no variadic inputs. + # Perhaps in the future we can support these. + if all(input.size == "1" for input in uop.stack.inputs): + # We can try a constant evaluation + out.emit("// Constant evaluation\n") + predicates = " && ".join( + [ + f"is_const({var.name})" + for var in mangled_uop.stack.inputs + if var.name not in UNUSED + ] + ) + + if predicates: + declare_caches(uop, out) + + out.emit(f"if ({predicates or 0}) {{\n") + declare_variables(uop, out, default_type="PyObject *") + for var, mangled_var in zip(uop.stack.inputs, mangled_uop.stack.inputs): + out.emit(f"{var.name} = get_const({mangled_var.name});\n") + emit_tokens(out, uop, stack, None, TIER2_REPLACEMENT_FUNCTIONS) + out.emit("\n") + const_val = f"(PyObject *){uop.stack.outputs[0].name}" + maybe_const_val = new_sym(const_val) + out.emit(f"{mangled_uop.stack.outputs[0].name} = {maybe_const_val}\n") + out.emit(f"if({mangled_uop.stack.outputs[0].name} == NULL) {{ goto error; }}\n") + out.emit(f"if (emit_const(&ctx->emitter, {const_val}, " + f"{len(uop.stack.inputs)}) < 0) {{ goto error; }}\n") + out.emit("new_inst.opcode = _NOP;\n") + out.emit("}\n") + if not mangled_uop.stack.outputs[0].peek: + out.emit("else {\n") + sym = new_sym(None) + out.emit(f"{mangled_uop.stack.outputs[0].name} = {sym}\n") + out.emit(f"if ({mangled_uop.stack.outputs[0].name} == NULL) {{ goto error; }}\n") + out.emit("}\n") + + out.emit(f"if ({mangled_uop.stack.outputs[0].name} == NULL) goto error;\n") + + # Perform type propagation + if (typ := uop.stack.outputs[0].type_prop) is not None: + typname, aux = typ + aux = "0" if aux is None else aux + out.emit("// Type propagation\n") + out.emit( + f"sym_set_type({mangled_uop.stack.outputs[0].name}, {typname}, (uint32_t){aux});" + ) + + +def _write_body_abstract_interp_guard_uop( + mangled_uop: Uop, uop: Uop, out: CWriter, stack: Stack +) -> None: + # 1. Attempt to perform guard elimination + # 2. Type propagate for guard success + if uop.name in NO_CONST_OR_TYPE_EVALUATE: + return + + out.emit("// Constant evaluation\n") + predicates_str = " && ".join( + [ + f"is_const({var.name})" + for var in mangled_uop.stack.inputs + if var.name not in UNUSED + ] + ) + if predicates_str: + declare_caches(uop, out) + out.emit(f"if ({predicates_str}) {{\n") + declare_variables(uop, out, default_type="PyObject *") + for var, mangled_var in zip(uop.stack.inputs, mangled_uop.stack.inputs): + if var.name in UNUSED: + continue + out.emit(f"{var.name} = get_const({mangled_var.name});\n") + emit_tokens(out, uop, stack, None, TIER2_REPLACEMENT_FUNCTIONS) + out.emit("\n") + # Guard elimination + out.emit('DPRINTF(3, "const eliminated guard\\n");\n') + out.emit("new_inst.opcode = _NOP;\n") + out.emit("break;\n") + out.emit("}\n") + + # Does the input specify typed inputs? + if not any(output_var.type_prop for output_var in mangled_uop.stack.outputs): + return + # If the input types already match, eliminate the guard + # Read the cache information to check the auxiliary type information + predicates = [] + propagates = [] + + assert len(mangled_uop.stack.outputs) == len( + mangled_uop.stack.inputs + ), "guards must have same number of args" + assert [ + output == input_ + for output, input_ in zip(mangled_uop.stack.outputs, mangled_uop.stack.inputs) + ], "guards must forward their stack values" + for output_var in mangled_uop.stack.outputs: + if output_var.name in UNUSED: + continue + if (typ := output_var.type_prop) is not None: + typname, aux = typ + aux = "0" if aux is None else aux + # Check that the input type information match (including auxiliary info) + predicates.append( + f"sym_matches_type((_Py_UOpsSymType *){output_var.name}, {typname}, (uint32_t){aux})" + ) + # Propagate mode - set the types + propagates.append( + f"sym_set_type((_Py_UOpsSymType *){output_var.name}, {typname}, (uint32_t){aux})" + ) + + out.emit("// Type guard elimination\n") + out.emit(f"if ({' && '.join(predicates)}) {{\n") + out.emit('DPRINTF(2, "type propagation eliminated guard\\n");\n') + out.emit("new_inst.opcode = _NOP;\n") + out.emit("break;\n") + out.emit("}\n") + # Else we need the guard + out.emit("else {\n") + out.emit("// Type propagation\n") + for prop in propagates: + out.emit(f"{prop};\n") + out.emit("}\n") + + +def write_abstract_uop(mangled_uop: Uop, uop: Uop, out: CWriter, stack: Stack) -> None: + try: + out.start_line() + is_impure = not mangled_uop.properties.pure and not mangled_uop.properties.guard + # These types of guards do not need the stack at all. + if not ( + mangled_uop.properties.guard + and mangled_uop.name in NO_CONST_OR_TYPE_EVALUATE + ): + for var in reversed(mangled_uop.stack.inputs): + definition = stack.pop(var) + if not is_impure: + out.emit(definition) + if not mangled_uop.properties.stores_sp: + for i, var in enumerate(mangled_uop.stack.outputs): + definition = stack.push(var) + if not (is_impure and var.size != "1"): + out.emit(definition) + if uop.properties.pure: + _write_body_abstract_interp_pure_uop(mangled_uop, uop, out, stack) + elif uop.properties.guard: + _write_body_abstract_interp_guard_uop(mangled_uop, uop, out, stack) + else: + _write_body_abstract_interp_impure_uop(mangled_uop, uop, out, stack) + except SizeMismatch as ex: + raise analysis_error(ex.args[0], uop.body[0]) + + +SKIPS = ("_EXTENDED_ARG",) + + +def generate_tier2_abstract( + filenames: list[str], analysis: Analysis, outfile: TextIO, lines: bool +) -> None: + write_header(__file__, filenames, outfile) + outfile.write( + """ +#ifdef TIER_ONE + #error "This file is for Tier 2 only" +#endif +#define TIER_TWO 2 +""" + ) + out = CWriter(outfile, 2, lines) + out.emit("\n") + for name, uop in analysis.uops.items(): + if name in SPECIALLY_HANDLED_ABSTRACT_INSTR: + continue + if uop.properties.tier_one_only: + continue + 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") + continue + out.emit(f"case {uop.name}: {{\n") + mangled_uop = mangle_uop_names(uop) + is_impure = not (mangled_uop.properties.pure or mangled_uop.properties.guard) + declare_variables(mangled_uop, out, skip_inputs=is_impure, skip_peeks=is_impure) + stack = Stack() + write_abstract_uop(mangled_uop, uop, out, stack) + out.start_line() + if not uop.properties.always_exits: + # Guards strictly only peek + if not uop.properties.guard: + stack.flush(out, cast_type="_Py_UOpsSymType *") + out.emit("break;\n") + out.start_line() + out.emit("}") + out.emit("\n\n") + outfile.write("#undef TIER_TWO\n") + + +arg_parser = argparse.ArgumentParser( + description="Generate the code for the tier 2 interpreter.", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, +) + +arg_parser.add_argument( + "-o", "--output", type=str, help="Generated code", default=DEFAULT_OUTPUT +) + +arg_parser.add_argument( + "-l", "--emit-line-directives", help="Emit #line directives", action="store_true" +) + +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_tier2_abstract(args.input, data, outfile, args.emit_line_directives) diff --git a/Tools/cases_generator/uop_metadata_generator.py b/Tools/cases_generator/uop_metadata_generator.py index 9083ecc48bdf5b..e5d74b436991c0 100644 --- a/Tools/cases_generator/uop_metadata_generator.py +++ b/Tools/cases_generator/uop_metadata_generator.py @@ -15,6 +15,7 @@ write_header, cflags, ) +from stack import Stack from cwriter import CWriter from typing import TextIO @@ -40,6 +41,25 @@ def generate_names_and_flags(analysis: Analysis, out: CWriter) -> None: out.emit("#endif // NEED_OPCODE_METADATA\n\n") +def generate_net_stack_effect(analysis: Analysis, out: CWriter) -> None: + out.emit("extern int _PyUop_NetStackEffect(int opcode, int oparg);\n") + out.emit("#ifdef NEED_OPCODE_METADATA\n") + out.emit("int _PyUop_NetStackEffect(int opcode, int oparg) {\n") + out.emit("switch (opcode) {\n") + for uop in analysis.uops.values(): + if uop.is_viable() and not uop.properties.tier_one_only: + out.emit(f"case {uop.name}:\n") + stack = Stack() + for inputs in uop.stack.inputs: + stack.pop(inputs) + for outputs in uop.stack.outputs: + stack.push(outputs) + out.emit(f"return ({stack.top_offset.to_c()});\n") + out.emit("default: Py_UNREACHABLE();\n") + out.emit("};\n") + out.emit("};\n\n") + out.emit("#endif // NEED_OPCODE_METADATA\n\n") + def generate_uop_metadata( filenames: list[str], analysis: Analysis, outfile: TextIO ) -> None: @@ -49,6 +69,7 @@ def generate_uop_metadata( out.emit("#include \n") out.emit('#include "pycore_uop_ids.h"\n') generate_names_and_flags(analysis, out) + generate_net_stack_effect(analysis, out) arg_parser = argparse.ArgumentParser( From e2703644740fb3dc881540bfffbf34d93c5f50d9 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 6 Feb 2024 15:30:05 +0800 Subject: [PATCH 02/52] Port over to Mark's DSL Co-Authored-By: Mark Shannon <9448417+markshannon@users.noreply.github.com> --- Include/internal/pycore_uop_ids.h | 3 +- Include/internal/pycore_uop_metadata.h | 488 +--- Lib/test/test_capi/test_opt.py | 203 +- Makefile.pre.in | 4 +- Python/abstract_interp_cases.c.h | 2306 +++++++++-------- Python/bytecodes.c | 14 +- Python/executor_cases.c.h | 11 - Python/optimizer_analysis.c | 294 +-- Python/pylifecycle.c | 2 +- .../tier2_redundancy_eliminator_bytecodes.c | 251 ++ Tools/cases_generator/analyzer.py | 10 - Tools/cases_generator/generators_common.py | 4 - .../cases_generator/tier2_abstract_common.py | 34 - .../tier2_abstract_generator.py | 476 +--- .../cases_generator/uop_metadata_generator.py | 22 - 15 files changed, 1643 insertions(+), 2479 deletions(-) create mode 100644 Python/tier2_redundancy_eliminator_bytecodes.c delete mode 100644 Tools/cases_generator/tier2_abstract_common.py diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index c5ecf99905b865..6c0b55f8b132fb 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -239,8 +239,7 @@ extern "C" { #define _CHECK_GLOBALS 386 #define _CHECK_BUILTINS 387 #define _INTERNAL_INCREMENT_OPT_COUNTER 388 -#define _SHRINK_STACK 389 -#define MAX_UOP_ID 389 +#define MAX_UOP_ID 388 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 6aed6163ca19b9..f333e0041c13ec 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -18,36 +18,36 @@ extern const char * const _PyOpcode_uop_name[MAX_UOP_ID+1]; const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_NOP] = HAS_PURE_FLAG, [_RESUME_CHECK] = HAS_DEOPT_FLAG, - [_LOAD_FAST_CHECK] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ERROR_FLAG | HAS_SPECIAL_OPT_FLAG, - [_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG | HAS_SPECIAL_OPT_FLAG, - [_LOAD_FAST_AND_CLEAR] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_SPECIAL_OPT_FLAG, + [_LOAD_FAST_CHECK] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ERROR_FLAG, + [_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG, + [_LOAD_FAST_AND_CLEAR] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, [_LOAD_FAST_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, - [_LOAD_CONST] = HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_PURE_FLAG | HAS_SPECIAL_OPT_FLAG, - [_STORE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_SPECIAL_OPT_FLAG, + [_LOAD_CONST] = HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_PURE_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] = HAS_PURE_FLAG, - [_PUSH_NULL] = HAS_PURE_FLAG | HAS_SPECIAL_OPT_FLAG, + [_PUSH_NULL] = HAS_PURE_FLAG, [_END_SEND] = HAS_PURE_FLAG, [_UNARY_NEGATIVE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_UNARY_NOT] = HAS_PURE_FLAG, [_TO_BOOL] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_TO_BOOL_BOOL] = HAS_DEOPT_FLAG | HAS_GUARD_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 | HAS_GUARD_FLAG, + [_GUARD_BOTH_INT] = HAS_DEOPT_FLAG, [_BINARY_OP_MULTIPLY_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, [_BINARY_OP_ADD_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, [_BINARY_OP_SUBTRACT_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, - [_GUARD_BOTH_FLOAT] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, + [_GUARD_BOTH_FLOAT] = HAS_DEOPT_FLAG, [_BINARY_OP_MULTIPLY_FLOAT] = HAS_PURE_FLAG, [_BINARY_OP_ADD_FLOAT] = HAS_PURE_FLAG, [_BINARY_OP_SUBTRACT_FLOAT] = HAS_PURE_FLAG, - [_GUARD_BOTH_UNICODE] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, + [_GUARD_BOTH_UNICODE] = HAS_DEOPT_FLAG, [_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_PURE_FLAG, [_BINARY_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_BINARY_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -64,7 +64,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_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 | HAS_SPECIAL_OPT_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, @@ -112,17 +112,17 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_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 | HAS_GUARD_FLAG, - [_CHECK_MANAGED_OBJECT_HAS_VALUES] = HAS_DEOPT_FLAG | HAS_GUARD_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 | HAS_GUARD_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 | HAS_GUARD_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 | HAS_GUARD_FLAG, + [_CHECK_ATTR_CLASS] = HAS_DEOPT_FLAG, [_LOAD_ATTR_CLASS] = HAS_ARG_FLAG, - [_GUARD_DORV_VALUES] = HAS_DEOPT_FLAG | HAS_GUARD_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, @@ -142,34 +142,34 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_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 | HAS_GUARD_FLAG, - [_GUARD_NOT_EXHAUSTED_LIST] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, + [_ITER_CHECK_LIST] = HAS_DEOPT_FLAG, + [_GUARD_NOT_EXHAUSTED_LIST] = HAS_DEOPT_FLAG, [_ITER_NEXT_LIST] = 0, - [_ITER_CHECK_TUPLE] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, - [_GUARD_NOT_EXHAUSTED_TUPLE] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, + [_ITER_CHECK_TUPLE] = HAS_DEOPT_FLAG, + [_GUARD_NOT_EXHAUSTED_TUPLE] = HAS_DEOPT_FLAG, [_ITER_NEXT_TUPLE] = 0, - [_ITER_CHECK_RANGE] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, - [_GUARD_NOT_EXHAUSTED_RANGE] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, + [_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 | HAS_GUARD_FLAG, - [_GUARD_KEYS_VERSION] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG, + [_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 | HAS_GUARD_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 | HAS_GUARD_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 | HAS_GUARD_FLAG | HAS_SPECIAL_OPT_FLAG, - [_CHECK_FUNCTION_EXACT_ARGS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_GUARD_FLAG, - [_CHECK_STACK_SPACE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_GUARD_FLAG, - [_INIT_CALL_PY_EXACT_ARGS] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG | HAS_PURE_FLAG | HAS_SPECIAL_OPT_FLAG, - [_PUSH_FRAME] = HAS_ESCAPES_FLAG | HAS_SPECIAL_OPT_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 | HAS_PURE_FLAG, + [_PUSH_FRAME] = HAS_ESCAPES_FLAG, [_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, @@ -190,7 +190,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_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 | HAS_PURE_FLAG | HAS_SPECIAL_OPT_FLAG, + [_COPY] = HAS_ARG_FLAG | HAS_PURE_FLAG, [_BINARY_OP] = HAS_ARG_FLAG | HAS_ERROR_FLAG, [_SWAP] = HAS_ARG_FLAG | HAS_PURE_FLAG, [_GUARD_IS_TRUE_POP] = HAS_DEOPT_FLAG, @@ -198,20 +198,19 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_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 | HAS_SPECIAL_OPT_FLAG, - [_SAVE_RETURN_OFFSET] = HAS_ARG_FLAG | HAS_SPECIAL_OPT_FLAG, + [_SET_IP] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, + [_SAVE_RETURN_OFFSET] = HAS_ARG_FLAG, [_EXIT_TRACE] = HAS_DEOPT_FLAG, [_JUMP_ABSOLUTE] = HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG, [_JUMP_ABSOLUTE_HEADER] = 0, - [_CHECK_VALIDITY] = HAS_DEOPT_FLAG | HAS_SPECIAL_OPT_FLAG, - [_LOAD_CONST_INLINE] = HAS_PURE_FLAG | HAS_SPECIAL_OPT_FLAG, - [_LOAD_CONST_INLINE_BORROW] = HAS_PURE_FLAG | HAS_SPECIAL_OPT_FLAG, - [_LOAD_CONST_INLINE_WITH_NULL] = HAS_PURE_FLAG | HAS_SPECIAL_OPT_FLAG, - [_LOAD_CONST_INLINE_BORROW_WITH_NULL] = HAS_PURE_FLAG | HAS_SPECIAL_OPT_FLAG, - [_CHECK_GLOBALS] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG | HAS_SPECIAL_OPT_FLAG, - [_CHECK_BUILTINS] = HAS_DEOPT_FLAG | HAS_GUARD_FLAG | HAS_SPECIAL_OPT_FLAG, + [_CHECK_VALIDITY] = HAS_DEOPT_FLAG, + [_LOAD_CONST_INLINE] = HAS_PURE_FLAG, + [_LOAD_CONST_INLINE_BORROW] = HAS_PURE_FLAG, + [_LOAD_CONST_INLINE_WITH_NULL] = HAS_PURE_FLAG, + [_LOAD_CONST_INLINE_BORROW_WITH_NULL] = HAS_PURE_FLAG, + [_CHECK_GLOBALS] = HAS_DEOPT_FLAG, + [_CHECK_BUILTINS] = HAS_DEOPT_FLAG, [_INTERNAL_INCREMENT_OPT_COUNTER] = 0, - [_SHRINK_STACK] = HAS_ARG_FLAG, }; const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { @@ -380,7 +379,6 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_SET_FUNCTION_ATTRIBUTE] = "_SET_FUNCTION_ATTRIBUTE", [_SET_IP] = "_SET_IP", [_SET_UPDATE] = "_SET_UPDATE", - [_SHRINK_STACK] = "_SHRINK_STACK", [_STORE_ATTR] = "_STORE_ATTR", [_STORE_ATTR_INSTANCE_VALUE] = "_STORE_ATTR_INSTANCE_VALUE", [_STORE_ATTR_SLOT] = "_STORE_ATTR_SLOT", @@ -414,408 +412,6 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { }; #endif // NEED_OPCODE_METADATA -extern int _PyUop_NetStackEffect(int opcode, int oparg); -#ifdef NEED_OPCODE_METADATA -int _PyUop_NetStackEffect(int opcode, int oparg) { - switch (opcode) { - case _NOP: - return (0); - case _RESUME_CHECK: - return (0); - case _LOAD_FAST_CHECK: - return (1); - case _LOAD_FAST: - return (1); - case _LOAD_FAST_AND_CLEAR: - return (1); - case _LOAD_FAST_LOAD_FAST: - return (2); - case _LOAD_CONST: - return (1); - case _STORE_FAST: - return (-1); - case _STORE_FAST_LOAD_FAST: - return (0); - case _STORE_FAST_STORE_FAST: - return (-2); - case _POP_TOP: - return (-1); - case _PUSH_NULL: - return (1); - case _END_SEND: - return (-1); - case _UNARY_NEGATIVE: - return (0); - case _UNARY_NOT: - return (0); - case _TO_BOOL: - return (0); - case _TO_BOOL_BOOL: - return (0); - case _TO_BOOL_INT: - return (0); - case _TO_BOOL_LIST: - return (0); - case _TO_BOOL_NONE: - return (0); - case _TO_BOOL_STR: - return (0); - case _TO_BOOL_ALWAYS_TRUE: - return (0); - case _UNARY_INVERT: - return (0); - case _GUARD_BOTH_INT: - return (0); - case _BINARY_OP_MULTIPLY_INT: - return (-1); - case _BINARY_OP_ADD_INT: - return (-1); - case _BINARY_OP_SUBTRACT_INT: - return (-1); - case _GUARD_BOTH_FLOAT: - return (0); - case _BINARY_OP_MULTIPLY_FLOAT: - return (-1); - case _BINARY_OP_ADD_FLOAT: - return (-1); - case _BINARY_OP_SUBTRACT_FLOAT: - return (-1); - case _GUARD_BOTH_UNICODE: - return (0); - case _BINARY_OP_ADD_UNICODE: - return (-1); - case _BINARY_SUBSCR: - return (-1); - case _BINARY_SLICE: - return (-2); - case _STORE_SLICE: - return (-4); - case _BINARY_SUBSCR_LIST_INT: - return (-1); - case _BINARY_SUBSCR_STR_INT: - return (-1); - case _BINARY_SUBSCR_TUPLE_INT: - return (-1); - case _BINARY_SUBSCR_DICT: - return (-1); - case _LIST_APPEND: - return (-1); - case _SET_ADD: - return (-1); - case _STORE_SUBSCR: - return (-3); - case _STORE_SUBSCR_LIST_INT: - return (-3); - case _STORE_SUBSCR_DICT: - return (-3); - case _DELETE_SUBSCR: - return (-2); - case _CALL_INTRINSIC_1: - return (0); - case _CALL_INTRINSIC_2: - return (-1); - case _POP_FRAME: - return (-1); - case _GET_AITER: - return (0); - case _GET_ANEXT: - return (1); - case _GET_AWAITABLE: - return (0); - case _POP_EXCEPT: - return (-1); - case _LOAD_ASSERTION_ERROR: - return (1); - case _LOAD_BUILD_CLASS: - return (1); - case _STORE_NAME: - return (-1); - case _DELETE_NAME: - return (0); - case _UNPACK_SEQUENCE: - return (-1 + oparg); - case _UNPACK_SEQUENCE_TWO_TUPLE: - return (-1 + oparg); - case _UNPACK_SEQUENCE_TUPLE: - return (-1 + oparg); - case _UNPACK_SEQUENCE_LIST: - return (-1 + oparg); - case _UNPACK_EX: - return ((oparg >> 8) + (oparg & 0xFF)); - case _STORE_ATTR: - return (-2); - case _DELETE_ATTR: - return (-1); - case _STORE_GLOBAL: - return (-1); - case _DELETE_GLOBAL: - return (0); - case _LOAD_LOCALS: - return (1); - case _LOAD_FROM_DICT_OR_GLOBALS: - return (0); - case _LOAD_NAME: - return (1); - case _LOAD_GLOBAL: - return (1 + (oparg & 1)); - case _GUARD_GLOBALS_VERSION: - return (0); - case _GUARD_BUILTINS_VERSION: - return (0); - case _LOAD_GLOBAL_MODULE: - return (1 + (oparg & 1)); - case _LOAD_GLOBAL_BUILTINS: - return (1 + (oparg & 1)); - case _DELETE_FAST: - return (0); - case _MAKE_CELL: - return (0); - case _DELETE_DEREF: - return (0); - case _LOAD_FROM_DICT_OR_DEREF: - return (0); - case _LOAD_DEREF: - return (1); - case _STORE_DEREF: - return (-1); - case _COPY_FREE_VARS: - return (0); - case _BUILD_STRING: - return (1 - oparg); - case _BUILD_TUPLE: - return (1 - oparg); - case _BUILD_LIST: - return (1 - oparg); - case _LIST_EXTEND: - return (-1); - case _SET_UPDATE: - return (-1); - case _BUILD_SET: - return (1 - oparg); - case _BUILD_MAP: - return (1 - oparg*2); - case _SETUP_ANNOTATIONS: - return (0); - case _BUILD_CONST_KEY_MAP: - return (-oparg); - case _DICT_UPDATE: - return (-1); - case _DICT_MERGE: - return (-1); - case _MAP_ADD: - return (-2); - case _LOAD_SUPER_ATTR_ATTR: - return (-2 + ((0) ? 1 : 0)); - case _LOAD_SUPER_ATTR_METHOD: - return (-1); - case _LOAD_ATTR: - return ((oparg & 1)); - case _GUARD_TYPE_VERSION: - return (0); - case _CHECK_MANAGED_OBJECT_HAS_VALUES: - return (0); - case _LOAD_ATTR_INSTANCE_VALUE: - return ((oparg & 1)); - case _CHECK_ATTR_MODULE: - return (0); - case _LOAD_ATTR_MODULE: - return ((oparg & 1)); - case _CHECK_ATTR_WITH_HINT: - return (0); - case _LOAD_ATTR_WITH_HINT: - return ((oparg & 1)); - case _LOAD_ATTR_SLOT: - return ((oparg & 1)); - case _CHECK_ATTR_CLASS: - return (0); - case _LOAD_ATTR_CLASS: - return ((oparg & 1)); - case _GUARD_DORV_VALUES: - return (0); - case _STORE_ATTR_INSTANCE_VALUE: - return (-2); - case _STORE_ATTR_SLOT: - return (-2); - case _COMPARE_OP: - return (-1); - case _COMPARE_OP_FLOAT: - return (-1); - case _COMPARE_OP_INT: - return (-1); - case _COMPARE_OP_STR: - return (-1); - case _IS_OP: - return (-1); - case _CONTAINS_OP: - return (-1); - case _CHECK_EG_MATCH: - return (0); - case _CHECK_EXC_MATCH: - return (0); - case _IS_NONE: - return (0); - case _GET_LEN: - return (1); - case _MATCH_CLASS: - return (-2); - case _MATCH_MAPPING: - return (1); - case _MATCH_SEQUENCE: - return (1); - case _MATCH_KEYS: - return (1); - case _GET_ITER: - return (0); - case _GET_YIELD_FROM_ITER: - return (0); - case _FOR_ITER_TIER_TWO: - return (1); - case _ITER_CHECK_LIST: - return (0); - case _GUARD_NOT_EXHAUSTED_LIST: - return (0); - case _ITER_NEXT_LIST: - return (1); - case _ITER_CHECK_TUPLE: - return (0); - case _GUARD_NOT_EXHAUSTED_TUPLE: - return (0); - case _ITER_NEXT_TUPLE: - return (1); - case _ITER_CHECK_RANGE: - return (0); - case _GUARD_NOT_EXHAUSTED_RANGE: - return (0); - case _ITER_NEXT_RANGE: - return (1); - case _BEFORE_ASYNC_WITH: - return (1); - case _BEFORE_WITH: - return (1); - case _WITH_EXCEPT_START: - return (1); - case _PUSH_EXC_INFO: - return (1); - case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT: - return (0); - case _GUARD_KEYS_VERSION: - return (0); - case _LOAD_ATTR_METHOD_WITH_VALUES: - return (((1) ? 1 : 0)); - case _LOAD_ATTR_METHOD_NO_DICT: - return (((1) ? 1 : 0)); - case _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: - return (((0) ? 1 : 0)); - case _LOAD_ATTR_NONDESCRIPTOR_NO_DICT: - return (((0) ? 1 : 0)); - case _CHECK_ATTR_METHOD_LAZY_DICT: - return (0); - case _LOAD_ATTR_METHOD_LAZY_DICT: - return (((1) ? 1 : 0)); - case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: - return (0); - case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: - return (0); - case _CHECK_PEP_523: - return (0); - case _CHECK_FUNCTION_EXACT_ARGS: - return (0); - case _CHECK_STACK_SPACE: - return (0); - case _INIT_CALL_PY_EXACT_ARGS: - return (-1 - oparg); - case _PUSH_FRAME: - return (-1 + ((0) ? 1 : 0)); - case _CALL_TYPE_1: - return (-1 - oparg); - case _CALL_STR_1: - return (-1 - oparg); - case _CALL_TUPLE_1: - return (-1 - oparg); - case _EXIT_INIT_CHECK: - return (-1); - case _CALL_BUILTIN_CLASS: - return (-1 - oparg); - case _CALL_BUILTIN_O: - return (-1 - oparg); - case _CALL_BUILTIN_FAST: - return (-1 - oparg); - case _CALL_BUILTIN_FAST_WITH_KEYWORDS: - return (-1 - oparg); - case _CALL_LEN: - return (-1 - oparg); - case _CALL_ISINSTANCE: - return (-1 - oparg); - case _CALL_METHOD_DESCRIPTOR_O: - return (-1 - oparg); - case _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: - return (-1 - oparg); - case _CALL_METHOD_DESCRIPTOR_NOARGS: - return (-1 - oparg); - case _CALL_METHOD_DESCRIPTOR_FAST: - return (-1 - oparg); - case _MAKE_FUNCTION: - return (0); - case _SET_FUNCTION_ATTRIBUTE: - return (-1); - case _BUILD_SLICE: - return (-1 - ((oparg == 3) ? 1 : 0)); - case _CONVERT_VALUE: - return (0); - case _FORMAT_SIMPLE: - return (0); - case _FORMAT_WITH_SPEC: - return (-1); - case _COPY: - return (1); - case _BINARY_OP: - return (-1); - case _SWAP: - return (0); - case _GUARD_IS_TRUE_POP: - return (-1); - case _GUARD_IS_FALSE_POP: - return (-1); - case _GUARD_IS_NONE_POP: - return (-1); - case _GUARD_IS_NOT_NONE_POP: - return (-1); - case _JUMP_TO_TOP: - return (0); - case _SET_IP: - return (0); - case _SAVE_RETURN_OFFSET: - return (0); - case _EXIT_TRACE: - return (0); - case _JUMP_ABSOLUTE: - return (0); - case _JUMP_ABSOLUTE_HEADER: - return (0); - case _CHECK_VALIDITY: - return (0); - case _LOAD_CONST_INLINE: - return (1); - case _LOAD_CONST_INLINE_BORROW: - return (1); - case _LOAD_CONST_INLINE_WITH_NULL: - return (2); - case _LOAD_CONST_INLINE_BORROW_WITH_NULL: - return (2); - case _CHECK_GLOBALS: - return (0); - case _CHECK_BUILTINS: - return (0); - case _INTERNAL_INCREMENT_OPT_COUNTER: - return (-1); - case _SHRINK_STACK: - return (-oparg); - default: Py_UNREACHABLE(); - }; -}; - -#endif // NEED_OPCODE_METADATA - #ifdef __cplusplus } diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 3b0c2532d72528..94a9bd30466eaa 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -545,49 +545,6 @@ def testfunc(n): class TestUopsOptimization(unittest.TestCase): - def test_int_constant_propagation(self): - def testfunc(loops): - num = 0 - for _ in range(loops): - x = 0 - y = 1 - a = x + y - return 1 - - opt = _testinternalcapi.get_uop_optimizer() - res = None - with temporary_optimizer(opt): - res = testfunc(64) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) - self.assertEqual(res, 1) - binop_count = [opname for opname, _, _ in ex if opname == "_BINARY_OP_ADD_INT"] - self.assertEqual(len(binop_count), 0) - uops = {opname for opname, _, _ in ex} - self.assertNotIn("_SHRINK_STACK", uops) - - def test_int_constant_propagation_many(self): - def testfunc(loops): - num = 0 - for _ in range(loops): - x = 0 - y = 1 - a = x + y + x + y + x + y + x + y - return a - - opt = _testinternalcapi.get_uop_optimizer() - res = None - with temporary_optimizer(opt): - res = testfunc(64) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) - self.assertEqual(res, 4) - binop_count = [opname for opname, _, _ in ex if opname == "_BINARY_OP_ADD_INT"] - self.assertEqual(len(binop_count), 0) - uops = {opname for opname, _, _ in ex} - self.assertNotIn("_SHRINK_STACK", uops) def test_int_type_propagation(self): def testfunc(loops): @@ -632,68 +589,6 @@ def testfunc(loops): binop_count = [opname for opname, _, _ in ex if opname == "_BINARY_OP_ADD_INT"] self.assertGreaterEqual(len(binop_count), 3) - def test_int_impure_region_attr(self): - class A: - foo = 1 - def testfunc(loops): - num = 0 - while num < loops: - x = A.foo + A.foo - y = 1 - A.foo - a = x + y - num += 1 - return a - - opt = _testinternalcapi.get_uop_optimizer() - res = None - with temporary_optimizer(opt): - res = testfunc(64) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) - binop_count = [opname for opname, _, _ in ex if opname == "_BINARY_OP_ADD_INT"] - self.assertGreaterEqual(len(binop_count), 3) - - def test_call_constant_propagate_past_impure(self): - def testfunc(n): - for i in range(n): - x = 1 - y = 1 - x // y - z = x + y - return z - - opt = _testinternalcapi.get_uop_optimizer() - with temporary_optimizer(opt): - res = testfunc(20) - - ex = get_first_executor(testfunc) - self.assertEqual(res, 2) - self.assertIsNotNone(ex) - uops = {opname for opname, _, _ in ex} - self.assertNotIn("_BINARY_OP_ADD_INT", uops) - - def test_int_large_pure_region(self): - def testfunc(loops): - num = 0 - while num < loops: - x = num + num + num - num + num - num + num + num + num - num + num - num - y = 1 - a = x + num + num + num - num += 1 - return a - - opt = _testinternalcapi.get_uop_optimizer() - res = None - with temporary_optimizer(opt): - res = testfunc(64) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) - binop_count = [opname for opname, _, _ in ex if opname == "_BINARY_OP_ADD_INT"] - self.assertGreaterEqual(len(binop_count), 11) - def test_call_py_exact_args(self): def testfunc(n): def dummy(x): @@ -712,86 +607,6 @@ def dummy(x): self.assertIn("_BINARY_OP_ADD_INT", uops) self.assertNotIn("_CHECK_PEP_523", uops) - def test_frame_instance_method(self): - class A: - def __init__(self): - self.a = 1 - def foo(self): - return self.a - - a = A() - def testfunc(n): - for i in range(n): - a.foo() - - opt = _testinternalcapi.get_uop_optimizer() - with temporary_optimizer(opt): - testfunc(32) - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) - uops = {opname for opname, _, _ in ex} - self.assertIn("_LOAD_ATTR_METHOD_WITH_VALUES", uops) - - def test_frame_class_method(self): - class A: - def __init__(self): - self.a = 1 - def foo(self): - return self.a - - def testfunc(n): - a = A() - for i in range(n): - A.foo(a) - - opt = _testinternalcapi.get_uop_optimizer() - with temporary_optimizer(opt): - testfunc(32) - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) - uops = {opname for opname, _, _ in ex} - self.assertIn("_LOAD_ATTR_CLASS", uops) - - def test_call_constant_propagate_in_frame(self): - def testfunc(n): - def dummy(): - x = 1 - y = 1 - return x+y - for i in range(n): - x = dummy() - return x - - opt = _testinternalcapi.get_uop_optimizer() - with temporary_optimizer(opt): - res = testfunc(20) - - ex = get_first_executor(testfunc) - self.assertEqual(res, 2) - self.assertIsNotNone(ex) - uops = {opname for opname, _, _ in ex} - self.assertIn("_PUSH_FRAME", uops) - self.assertNotIn("_BINARY_OP_ADD_INT", uops) - - def test_call_constant_propagate_through_frame(self): - def testfunc(n): - def dummy(x): - return x+1 - for i in range(n): - x = dummy(3) - return x - - opt = _testinternalcapi.get_uop_optimizer() - with temporary_optimizer(opt): - res = testfunc(20) - - ex = get_first_executor(testfunc) - self.assertEqual(res, 4) - self.assertIsNotNone(ex) - uops = {opname for opname, _, _ in ex} - self.assertIn("_PUSH_FRAME", uops) - self.assertNotIn("_BINARY_OP_ADD_INT", uops) - def test_int_type_propagate_through_range(self): def testfunc(n): @@ -809,7 +624,7 @@ def testfunc(n): uops = {opname for opname, _, _ in ex} self.assertNotIn("_GUARD_BOTH_INT", uops) - def test_int_value_nubmering(self): + def test_int_value_numbering(self): def testfunc(n): y = 1 @@ -912,22 +727,6 @@ def testfunc(n): self.assertNotIn("_LOAD_GLOBAL_BUILTIN", uops) self.assertIn("_LOAD_CONST_INLINE_BORROW_WITH_NULL", uops) - def test_promote_globals_to_constants_propagate(self): - def testfunc(n): - for i in range(n): - x = Foo.attr - return x - - opt = _testinternalcapi.get_uop_optimizer() - with temporary_optimizer(opt): - res = testfunc(20) - - self.assertEqual(res, Foo.attr) - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) - uops = {opname for opname, _, _ in ex} - self.assertNotIn("_CHECK_ATTR_CLASS", uops) - self.assertIn("_LOAD_ATTR_CLASS", uops) class Foo: diff --git a/Makefile.pre.in b/Makefile.pre.in index 6b3c5026eff25c..1c0e49e39e88b2 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1606,7 +1606,9 @@ regen-cases: $(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/tier2_abstract_generator.py \ - -o $(srcdir)/Python/abstract_interp_cases.c.h.new $(srcdir)/Python/bytecodes.c + -o $(srcdir)/Python/abstract_interp_cases.c.h.new \ + $(srcdir)/Python/tier2_redundancy_eliminator_bytecodes.c \ + $(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 \ diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index bfedfb6da60581..8bdba5efaba916 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -1,13 +1,8 @@ // This file is generated by Tools/cases_generator/tier2_abstract_generator.py // from: -// Python/bytecodes.c +// Python/tier2_redundancy_eliminator_bytecodes.c // Do not edit! -#ifdef TIER_ONE - #error "This file is for Tier 2 only" -#endif -#define TIER_TWO 2 - case _NOP: { break; } @@ -18,531 +13,402 @@ /* _INSTRUMENTED_RESUME is not a viable micro-op for tier 2 */ + case _LOAD_FAST_CHECK: { + _Py_UOpsSymType *value; + value = GETLOCAL(oparg); + // We guarantee this will error - just bail and don't optimize it. + if (sym_is_type(value, NULL_TYPE)) { + goto error; + } + stack_pointer[0] = value; + stack_pointer += 1; + break; + } + + case _LOAD_FAST: { + _Py_UOpsSymType *value; + value = GETLOCAL(oparg); + stack_pointer[0] = value; + stack_pointer += 1; + break; + } + + case _LOAD_FAST_AND_CLEAR: { + _Py_UOpsSymType *value; + value = GETLOCAL(oparg); + _Py_UOpsSymType *temp = sym_init_null(ctx); + if (temp == NULL) { + goto error; + } + GETLOCAL(oparg) = temp; + stack_pointer[0] = value; + stack_pointer += 1; + break; + } + + case _LOAD_CONST: { + _Py_UOpsSymType *value; + value = GETITEM(ctx, oparg); + stack_pointer[0] = value; + stack_pointer += 1; + break; + } + + case _STORE_FAST: { + _Py_UOpsSymType *value; + value = stack_pointer[-1]; + GETLOCAL(oparg) = value; + stack_pointer += -1; + break; + } + case _POP_TOP: { - _Py_UOpsSymType *__value_; - __value_ = stack_pointer[-1]; - (void)__value_; + _Py_UOpsSymType *value; + value = stack_pointer[-1]; stack_pointer += -1; break; } + case _PUSH_NULL: { + _Py_UOpsSymType *res; + res = sym_init_null(ctx); + if (res == NULL) { + goto error; + }; + stack_pointer[0] = res; + stack_pointer += 1; + break; + } + case _END_SEND: { - _Py_UOpsSymType *__value_; - _Py_UOpsSymType *__receiver_; - __value_ = stack_pointer[-1]; - __receiver_ = stack_pointer[-2]; - (void)__receiver_; - (void)__value_; - stack_pointer[-2] = __value_; + _Py_UOpsSymType *value; + _Py_UOpsSymType *receiver; + value = stack_pointer[-1]; + receiver = stack_pointer[-2]; + value = sym_init_unknown(ctx); + if (value == NULL) goto error; + stack_pointer[-2] = value; stack_pointer += -1; break; } case _UNARY_NEGATIVE: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-1] = __res_; + _Py_UOpsSymType *value; + _Py_UOpsSymType *res; + value = stack_pointer[-1]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-1] = res; break; } case _UNARY_NOT: { - _Py_UOpsSymType *__value_; - _Py_UOpsSymType *__res_; - __value_ = stack_pointer[-1]; - // Constant evaluation - if (is_const(__value_)) { - PyObject *value; - PyObject *res; - value = get_const(__value_); - assert(PyBool_Check(value)); - res = Py_IsFalse(value) ? Py_True : Py_False; - __res_ = _Py_UOpsSymType_New(ctx, (PyObject *)res); - if(__res_ == NULL) { goto error; } - if (emit_const(&ctx->emitter, (PyObject *)res, 1) < 0) { goto error; } - new_inst.opcode = _NOP; - } - else { - __res_ = _Py_UOpsSymType_New(ctx, NULL); - if (__res_ == NULL) { goto error; } - } - if (__res_ == NULL) goto error; - stack_pointer[-1] = __res_; + _Py_UOpsSymType *value; + _Py_UOpsSymType *res; + value = stack_pointer[-1]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-1] = res; break; } case _TO_BOOL: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-1] = __res_; + _Py_UOpsSymType *value; + _Py_UOpsSymType *res; + value = stack_pointer[-1]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-1] = res; break; } case _TO_BOOL_BOOL: { - _Py_UOpsSymType *__value_; - __value_ = stack_pointer[-1]; - // Constant evaluation - if (is_const(__value_)) { - PyObject *value; - value = get_const(__value_); - if (!PyBool_Check(value)) goto error; - STAT_INC(TO_BOOL, hit); - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } break; } case _TO_BOOL_INT: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-1] = __res_; + _Py_UOpsSymType *value; + _Py_UOpsSymType *res; + value = stack_pointer[-1]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-1] = res; break; } case _TO_BOOL_LIST: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-1] = __res_; + _Py_UOpsSymType *value; + _Py_UOpsSymType *res; + value = stack_pointer[-1]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-1] = res; break; } case _TO_BOOL_NONE: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-1] = __res_; + _Py_UOpsSymType *value; + _Py_UOpsSymType *res; + value = stack_pointer[-1]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-1] = res; break; } case _TO_BOOL_STR: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-1] = __res_; + _Py_UOpsSymType *value; + _Py_UOpsSymType *res; + value = stack_pointer[-1]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-1] = res; break; } case _TO_BOOL_ALWAYS_TRUE: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-1] = __res_; + _Py_UOpsSymType *value; + _Py_UOpsSymType *res; + value = stack_pointer[-1]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-1] = res; break; } case _UNARY_INVERT: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-1] = __res_; + _Py_UOpsSymType *value; + _Py_UOpsSymType *res; + value = stack_pointer[-1]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-1] = res; break; } case _GUARD_BOTH_INT: { - _Py_UOpsSymType *__right_; - _Py_UOpsSymType *__left_; - __right_ = stack_pointer[-1]; - __left_ = stack_pointer[-2]; - // Constant evaluation - if (is_const(__left_) && is_const(__right_)) { - PyObject *right; - PyObject *left; - left = get_const(__left_); - right = get_const(__right_); - if (!PyLong_CheckExact(left)) goto error; - if (!PyLong_CheckExact(right)) goto error; - - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } - // Type guard elimination - if (sym_matches_type((_Py_UOpsSymType *)__left_, PYLONG_TYPE, (uint32_t)0) && sym_matches_type((_Py_UOpsSymType *)__right_, PYLONG_TYPE, (uint32_t)0)) { - DPRINTF(2, "type propagation eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } - else { - // Type propagation - sym_set_type((_Py_UOpsSymType *)__left_, PYLONG_TYPE, (uint32_t)0); - sym_set_type((_Py_UOpsSymType *)__right_, PYLONG_TYPE, (uint32_t)0); + _Py_UOpsSymType *right; + _Py_UOpsSymType *left; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + if (sym_matches_type(left, PYLONG_TYPE, 0) && + sym_matches_type(right, PYLONG_TYPE, 0)) { + REPLACE_OP(_NOP, 0, 0); } break; } case _BINARY_OP_MULTIPLY_INT: { - _Py_UOpsSymType *__right_; - _Py_UOpsSymType *__left_; - _Py_UOpsSymType *__res_; - __right_ = stack_pointer[-1]; - __left_ = stack_pointer[-2]; - // Constant evaluation - if (is_const(__left_) && is_const(__right_)) { - PyObject *right; - PyObject *left; - PyObject *res; - left = get_const(__left_); - right = get_const(__right_); - STAT_INC(BINARY_OP, hit); - res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); - _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - if (res == NULL) goto pop_2_error_tier_two; - - __res_ = _Py_UOpsSymType_New(ctx, (PyObject *)res); - if(__res_ == NULL) { goto error; } - if (emit_const(&ctx->emitter, (PyObject *)res, 2) < 0) { goto error; } - new_inst.opcode = _NOP; - } - else { - __res_ = _Py_UOpsSymType_New(ctx, NULL); - if (__res_ == NULL) { goto error; } - } - if (__res_ == NULL) goto error; - // Type propagation - sym_set_type(__res_, PYLONG_TYPE, (uint32_t)0); - stack_pointer[-2] = __res_; + _Py_UOpsSymType *right; + _Py_UOpsSymType *left; + _Py_UOpsSymType *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2] = res; stack_pointer += -1; break; } case _BINARY_OP_ADD_INT: { - _Py_UOpsSymType *__right_; - _Py_UOpsSymType *__left_; - _Py_UOpsSymType *__res_; - __right_ = stack_pointer[-1]; - __left_ = stack_pointer[-2]; - // Constant evaluation - if (is_const(__left_) && is_const(__right_)) { - PyObject *right; - PyObject *left; - PyObject *res; - left = get_const(__left_); - right = get_const(__right_); - STAT_INC(BINARY_OP, hit); - res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); - _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - if (res == NULL) goto pop_2_error_tier_two; - - __res_ = _Py_UOpsSymType_New(ctx, (PyObject *)res); - if(__res_ == NULL) { goto error; } - if (emit_const(&ctx->emitter, (PyObject *)res, 2) < 0) { goto error; } - new_inst.opcode = _NOP; + _Py_UOpsSymType *right; + _Py_UOpsSymType *left; + _Py_UOpsSymType *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + // TODO constant propagation + (void)left; + (void)right; + res = sym_init_unknown(ctx); + if (res == NULL) { + goto error; } - else { - __res_ = _Py_UOpsSymType_New(ctx, NULL); - if (__res_ == NULL) { goto error; } - } - if (__res_ == NULL) goto error; - // Type propagation - sym_set_type(__res_, PYLONG_TYPE, (uint32_t)0); - stack_pointer[-2] = __res_; + stack_pointer[-2] = res; stack_pointer += -1; break; } case _BINARY_OP_SUBTRACT_INT: { - _Py_UOpsSymType *__right_; - _Py_UOpsSymType *__left_; - _Py_UOpsSymType *__res_; - __right_ = stack_pointer[-1]; - __left_ = stack_pointer[-2]; - // Constant evaluation - if (is_const(__left_) && is_const(__right_)) { - PyObject *right; - PyObject *left; - PyObject *res; - left = get_const(__left_); - right = get_const(__right_); - STAT_INC(BINARY_OP, hit); - res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); - _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - if (res == NULL) goto pop_2_error_tier_two; - - __res_ = _Py_UOpsSymType_New(ctx, (PyObject *)res); - if(__res_ == NULL) { goto error; } - if (emit_const(&ctx->emitter, (PyObject *)res, 2) < 0) { goto error; } - new_inst.opcode = _NOP; - } - else { - __res_ = _Py_UOpsSymType_New(ctx, NULL); - if (__res_ == NULL) { goto error; } - } - if (__res_ == NULL) goto error; - // Type propagation - sym_set_type(__res_, PYLONG_TYPE, (uint32_t)0); - stack_pointer[-2] = __res_; + _Py_UOpsSymType *right; + _Py_UOpsSymType *left; + _Py_UOpsSymType *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2] = res; stack_pointer += -1; break; } case _GUARD_BOTH_FLOAT: { - _Py_UOpsSymType *__right_; - _Py_UOpsSymType *__left_; - __right_ = stack_pointer[-1]; - __left_ = stack_pointer[-2]; - // Constant evaluation - if (is_const(__left_) && is_const(__right_)) { - PyObject *right; - PyObject *left; - left = get_const(__left_); - right = get_const(__right_); - if (!PyFloat_CheckExact(left)) goto error; - if (!PyFloat_CheckExact(right)) goto error; - - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } - // Type guard elimination - if (sym_matches_type((_Py_UOpsSymType *)__left_, PYFLOAT_TYPE, (uint32_t)0) && sym_matches_type((_Py_UOpsSymType *)__right_, PYFLOAT_TYPE, (uint32_t)0)) { - DPRINTF(2, "type propagation eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } - else { - // Type propagation - sym_set_type((_Py_UOpsSymType *)__left_, PYFLOAT_TYPE, (uint32_t)0); - sym_set_type((_Py_UOpsSymType *)__right_, PYFLOAT_TYPE, (uint32_t)0); + _Py_UOpsSymType *right; + _Py_UOpsSymType *left; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + if (sym_matches_type(left, PYFLOAT_TYPE, 0) && + sym_matches_type(right, PYFLOAT_TYPE, 0)) { + REPLACE_OP(_NOP, 0 ,0); } break; } case _BINARY_OP_MULTIPLY_FLOAT: { - _Py_UOpsSymType *__right_; - _Py_UOpsSymType *__left_; - _Py_UOpsSymType *__res_; - __right_ = stack_pointer[-1]; - __left_ = stack_pointer[-2]; - // Constant evaluation - if (is_const(__left_) && is_const(__right_)) { - PyObject *right; - PyObject *left; - PyObject *res; - left = get_const(__left_); - right = get_const(__right_); - STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left)->ob_fval * - ((PyFloatObject *)right)->ob_fval; - DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - __res_ = _Py_UOpsSymType_New(ctx, (PyObject *)res); - if(__res_ == NULL) { goto error; } - if (emit_const(&ctx->emitter, (PyObject *)res, 2) < 0) { goto error; } - new_inst.opcode = _NOP; - } - else { - __res_ = _Py_UOpsSymType_New(ctx, NULL); - if (__res_ == NULL) { goto error; } - } - if (__res_ == NULL) goto error; - // Type propagation - sym_set_type(__res_, PYFLOAT_TYPE, (uint32_t)0); - stack_pointer[-2] = __res_; + _Py_UOpsSymType *right; + _Py_UOpsSymType *left; + _Py_UOpsSymType *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + sym_set_type(res, PYFLOAT_TYPE, 0); + stack_pointer[-2] = res; stack_pointer += -1; break; } case _BINARY_OP_ADD_FLOAT: { - _Py_UOpsSymType *__right_; - _Py_UOpsSymType *__left_; - _Py_UOpsSymType *__res_; - __right_ = stack_pointer[-1]; - __left_ = stack_pointer[-2]; - // Constant evaluation - if (is_const(__left_) && is_const(__right_)) { - PyObject *right; - PyObject *left; - PyObject *res; - left = get_const(__left_); - right = get_const(__right_); - STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left)->ob_fval + - ((PyFloatObject *)right)->ob_fval; - DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - __res_ = _Py_UOpsSymType_New(ctx, (PyObject *)res); - if(__res_ == NULL) { goto error; } - if (emit_const(&ctx->emitter, (PyObject *)res, 2) < 0) { goto error; } - new_inst.opcode = _NOP; - } - else { - __res_ = _Py_UOpsSymType_New(ctx, NULL); - if (__res_ == NULL) { goto error; } - } - if (__res_ == NULL) goto error; - // Type propagation - sym_set_type(__res_, PYFLOAT_TYPE, (uint32_t)0); - stack_pointer[-2] = __res_; + _Py_UOpsSymType *right; + _Py_UOpsSymType *left; + _Py_UOpsSymType *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + sym_set_type(res, PYFLOAT_TYPE, 0); + stack_pointer[-2] = res; stack_pointer += -1; break; } case _BINARY_OP_SUBTRACT_FLOAT: { - _Py_UOpsSymType *__right_; - _Py_UOpsSymType *__left_; - _Py_UOpsSymType *__res_; - __right_ = stack_pointer[-1]; - __left_ = stack_pointer[-2]; - // Constant evaluation - if (is_const(__left_) && is_const(__right_)) { - PyObject *right; - PyObject *left; - PyObject *res; - left = get_const(__left_); - right = get_const(__right_); - STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left)->ob_fval - - ((PyFloatObject *)right)->ob_fval; - DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - __res_ = _Py_UOpsSymType_New(ctx, (PyObject *)res); - if(__res_ == NULL) { goto error; } - if (emit_const(&ctx->emitter, (PyObject *)res, 2) < 0) { goto error; } - new_inst.opcode = _NOP; - } - else { - __res_ = _Py_UOpsSymType_New(ctx, NULL); - if (__res_ == NULL) { goto error; } - } - if (__res_ == NULL) goto error; - // Type propagation - sym_set_type(__res_, PYFLOAT_TYPE, (uint32_t)0); - stack_pointer[-2] = __res_; + _Py_UOpsSymType *right; + _Py_UOpsSymType *left; + _Py_UOpsSymType *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + sym_set_type(res, PYFLOAT_TYPE, 0); + stack_pointer[-2] = res; stack_pointer += -1; break; } case _GUARD_BOTH_UNICODE: { - _Py_UOpsSymType *__right_; - _Py_UOpsSymType *__left_; - __right_ = stack_pointer[-1]; - __left_ = stack_pointer[-2]; - // Constant evaluation - if (is_const(__left_) && is_const(__right_)) { - PyObject *right; - PyObject *left; - left = get_const(__left_); - right = get_const(__right_); - if (!PyUnicode_CheckExact(left)) goto error; - if (!PyUnicode_CheckExact(right)) goto error; - - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } - // Type guard elimination - if (sym_matches_type((_Py_UOpsSymType *)__left_, PYUNICODE_TYPE, (uint32_t)0) && sym_matches_type((_Py_UOpsSymType *)__right_, PYUNICODE_TYPE, (uint32_t)0)) { - DPRINTF(2, "type propagation eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } - else { - // Type propagation - sym_set_type((_Py_UOpsSymType *)__left_, PYUNICODE_TYPE, (uint32_t)0); - sym_set_type((_Py_UOpsSymType *)__right_, PYUNICODE_TYPE, (uint32_t)0); - } + _Py_UOpsSymType *right; + _Py_UOpsSymType *left; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + sym_set_type(left, PYUNICODE_TYPE, 0); + sym_set_type(right, PYUNICODE_TYPE, 0); break; } case _BINARY_OP_ADD_UNICODE: { - _Py_UOpsSymType *__right_; - _Py_UOpsSymType *__left_; - _Py_UOpsSymType *__res_; - __right_ = stack_pointer[-1]; - __left_ = stack_pointer[-2]; - // Constant evaluation - if (is_const(__left_) && is_const(__right_)) { - PyObject *right; - PyObject *left; - PyObject *res; - left = get_const(__left_); - right = get_const(__right_); - STAT_INC(BINARY_OP, hit); - res = PyUnicode_Concat(left, right); - _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); - _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - if (res == NULL) goto pop_2_error_tier_two; - - __res_ = _Py_UOpsSymType_New(ctx, (PyObject *)res); - if(__res_ == NULL) { goto error; } - if (emit_const(&ctx->emitter, (PyObject *)res, 2) < 0) { goto error; } - new_inst.opcode = _NOP; - } - else { - __res_ = _Py_UOpsSymType_New(ctx, NULL); - if (__res_ == NULL) { goto error; } - } - if (__res_ == NULL) goto error; - // Type propagation - sym_set_type(__res_, PYUNICODE_TYPE, (uint32_t)0); - stack_pointer[-2] = __res_; + _Py_UOpsSymType *right; + _Py_UOpsSymType *left; + _Py_UOpsSymType *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + sym_set_type(res, PYUNICODE_TYPE, 0); + stack_pointer[-2] = res; stack_pointer += -1; break; } case _BINARY_SUBSCR: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2] = __res_; + _Py_UOpsSymType *sub; + _Py_UOpsSymType *container; + _Py_UOpsSymType *res; + sub = stack_pointer[-1]; + container = stack_pointer[-2]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2] = res; stack_pointer += -1; break; } case _BINARY_SLICE: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-3] = __res_; + _Py_UOpsSymType *stop; + _Py_UOpsSymType *start; + _Py_UOpsSymType *container; + _Py_UOpsSymType *res; + stop = stack_pointer[-1]; + start = stack_pointer[-2]; + container = stack_pointer[-3]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-3] = res; stack_pointer += -2; break; } case _STORE_SLICE: { + _Py_UOpsSymType *stop; + _Py_UOpsSymType *start; + _Py_UOpsSymType *container; + _Py_UOpsSymType *v; + stop = stack_pointer[-1]; + start = stack_pointer[-2]; + container = stack_pointer[-3]; + v = stack_pointer[-4]; stack_pointer += -4; break; } case _BINARY_SUBSCR_LIST_INT: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2] = __res_; + _Py_UOpsSymType *sub; + _Py_UOpsSymType *list; + _Py_UOpsSymType *res; + sub = stack_pointer[-1]; + list = stack_pointer[-2]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2] = res; stack_pointer += -1; break; } case _BINARY_SUBSCR_STR_INT: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2] = __res_; + _Py_UOpsSymType *sub; + _Py_UOpsSymType *str; + _Py_UOpsSymType *res; + sub = stack_pointer[-1]; + str = stack_pointer[-2]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2] = res; stack_pointer += -1; break; } case _BINARY_SUBSCR_TUPLE_INT: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2] = __res_; + _Py_UOpsSymType *sub; + _Py_UOpsSymType *tuple; + _Py_UOpsSymType *res; + sub = stack_pointer[-1]; + tuple = stack_pointer[-2]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2] = res; stack_pointer += -1; break; } case _BINARY_SUBSCR_DICT: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2] = __res_; + _Py_UOpsSymType *sub; + _Py_UOpsSymType *dict; + _Py_UOpsSymType *res; + sub = stack_pointer[-1]; + dict = stack_pointer[-2]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2] = res; stack_pointer += -1; break; } @@ -550,78 +416,128 @@ /* _BINARY_SUBSCR_GETITEM is not a viable micro-op for tier 2 */ case _LIST_APPEND: { + _Py_UOpsSymType *v; + v = stack_pointer[-1]; stack_pointer += -1; break; } case _SET_ADD: { + _Py_UOpsSymType *v; + v = stack_pointer[-1]; stack_pointer += -1; break; } case _STORE_SUBSCR: { + _Py_UOpsSymType *sub; + _Py_UOpsSymType *container; + _Py_UOpsSymType *v; + sub = stack_pointer[-1]; + container = stack_pointer[-2]; + v = stack_pointer[-3]; stack_pointer += -3; break; } case _STORE_SUBSCR_LIST_INT: { + _Py_UOpsSymType *sub; + _Py_UOpsSymType *list; + _Py_UOpsSymType *value; + sub = stack_pointer[-1]; + list = stack_pointer[-2]; + value = stack_pointer[-3]; stack_pointer += -3; break; } case _STORE_SUBSCR_DICT: { + _Py_UOpsSymType *sub; + _Py_UOpsSymType *dict; + _Py_UOpsSymType *value; + sub = stack_pointer[-1]; + dict = stack_pointer[-2]; + value = stack_pointer[-3]; stack_pointer += -3; break; } case _DELETE_SUBSCR: { + _Py_UOpsSymType *sub; + _Py_UOpsSymType *container; + sub = stack_pointer[-1]; + container = stack_pointer[-2]; stack_pointer += -2; break; } case _CALL_INTRINSIC_1: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-1] = __res_; + _Py_UOpsSymType *value; + _Py_UOpsSymType *res; + value = stack_pointer[-1]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-1] = res; break; } case _CALL_INTRINSIC_2: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2] = __res_; + _Py_UOpsSymType *value1; + _Py_UOpsSymType *value2; + _Py_UOpsSymType *res; + value1 = stack_pointer[-1]; + value2 = stack_pointer[-2]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2] = res; stack_pointer += -1; break; } + case _POP_FRAME: { + _Py_UOpsSymType *retval; + _Py_UOpsSymType *res; + retval = stack_pointer[-1]; + stack_pointer += -1; + ctx->frame->stack_pointer = stack_pointer; + ctx_frame_pop(ctx); + stack_pointer = ctx->frame->stack_pointer; + res = retval; + stack_pointer[0] = res; + stack_pointer += 1; + break; + } + /* _INSTRUMENTED_RETURN_VALUE is not a viable micro-op for tier 2 */ /* _INSTRUMENTED_RETURN_CONST is not a viable micro-op for tier 2 */ case _GET_AITER: { - _Py_UOpsSymType *__iter_; - __iter_ = sym_init_unknown(ctx); - if(__iter_ == NULL) goto error; - stack_pointer[-1] = __iter_; + _Py_UOpsSymType *obj; + _Py_UOpsSymType *iter; + obj = stack_pointer[-1]; + iter = sym_init_unknown(ctx); + if (iter == NULL) goto error; + stack_pointer[-1] = iter; break; } case _GET_ANEXT: { - _Py_UOpsSymType *__awaitable_; - __awaitable_ = sym_init_unknown(ctx); - if(__awaitable_ == NULL) goto error; - stack_pointer[0] = __awaitable_; + _Py_UOpsSymType *awaitable; + awaitable = sym_init_unknown(ctx); + if (awaitable == NULL) goto error; + stack_pointer[0] = awaitable; stack_pointer += 1; break; } case _GET_AWAITABLE: { - _Py_UOpsSymType *__iter_; - __iter_ = sym_init_unknown(ctx); - if(__iter_ == NULL) goto error; - stack_pointer[-1] = __iter_; + _Py_UOpsSymType *iterable; + _Py_UOpsSymType *iter; + iterable = stack_pointer[-1]; + iter = sym_init_unknown(ctx); + if (iter == NULL) goto error; + stack_pointer[-1] = iter; break; } @@ -632,29 +548,33 @@ /* _INSTRUMENTED_YIELD_VALUE is not a viable micro-op for tier 2 */ case _POP_EXCEPT: { + _Py_UOpsSymType *exc_value; + exc_value = stack_pointer[-1]; stack_pointer += -1; break; } case _LOAD_ASSERTION_ERROR: { - _Py_UOpsSymType *__value_; - __value_ = sym_init_unknown(ctx); - if(__value_ == NULL) goto error; - stack_pointer[0] = __value_; + _Py_UOpsSymType *value; + value = sym_init_unknown(ctx); + if (value == NULL) goto error; + stack_pointer[0] = value; stack_pointer += 1; break; } case _LOAD_BUILD_CLASS: { - _Py_UOpsSymType *__bc_; - __bc_ = sym_init_unknown(ctx); - if(__bc_ == NULL) goto error; - stack_pointer[0] = __bc_; + _Py_UOpsSymType *bc; + bc = sym_init_unknown(ctx); + if (bc == NULL) goto error; + stack_pointer[0] = bc; stack_pointer += 1; break; } case _STORE_NAME: { + _Py_UOpsSymType *v; + v = stack_pointer[-1]; stack_pointer += -1; break; } @@ -664,65 +584,87 @@ } case _UNPACK_SEQUENCE: { - for (int case_gen_i = 0; case_gen_i < (oparg); case_gen_i++) { - *(stack_pointer + case_gen_i) = sym_init_unknown(ctx); - if(*(stack_pointer + case_gen_i) == NULL) goto error; - } + _Py_UOpsSymType *seq; + seq = stack_pointer[-1]; stack_pointer += -1 + oparg; break; } case _UNPACK_SEQUENCE_TWO_TUPLE: { - for (int case_gen_i = 0; case_gen_i < (oparg); case_gen_i++) { - *(stack_pointer + case_gen_i) = sym_init_unknown(ctx); - if(*(stack_pointer + case_gen_i) == NULL) goto error; + _Py_UOpsSymType *seq; + _Py_UOpsSymType **values; + seq = stack_pointer[-1]; + values = &stack_pointer[-1]; + for (int _i = oparg; --_i >= 0;) { + values[_i] = sym_init_unknown(ctx); + if (values[_i] == NULL) goto error; } stack_pointer += -1 + oparg; break; } case _UNPACK_SEQUENCE_TUPLE: { - for (int case_gen_i = 0; case_gen_i < (oparg); case_gen_i++) { - *(stack_pointer + case_gen_i) = sym_init_unknown(ctx); - if(*(stack_pointer + case_gen_i) == NULL) goto error; + _Py_UOpsSymType *seq; + _Py_UOpsSymType **values; + seq = stack_pointer[-1]; + values = &stack_pointer[-1]; + for (int _i = oparg; --_i >= 0;) { + values[_i] = sym_init_unknown(ctx); + if (values[_i] == NULL) goto error; } stack_pointer += -1 + oparg; break; } case _UNPACK_SEQUENCE_LIST: { - for (int case_gen_i = 0; case_gen_i < (oparg); case_gen_i++) { - *(stack_pointer + case_gen_i) = sym_init_unknown(ctx); - if(*(stack_pointer + case_gen_i) == NULL) goto error; + _Py_UOpsSymType *seq; + _Py_UOpsSymType **values; + seq = stack_pointer[-1]; + values = &stack_pointer[-1]; + for (int _i = oparg; --_i >= 0;) { + values[_i] = sym_init_unknown(ctx); + if (values[_i] == NULL) goto error; } stack_pointer += -1 + oparg; break; } case _UNPACK_EX: { - for (int case_gen_i = 0; case_gen_i < (oparg & 0xFF); case_gen_i++) { - *(stack_pointer + case_gen_i) = sym_init_unknown(ctx); - if(*(stack_pointer + case_gen_i) == NULL) goto error; - } - for (int case_gen_i = 0; case_gen_i < (oparg >> 8); case_gen_i++) { - *(stack_pointer + case_gen_i) = sym_init_unknown(ctx); - if(*(stack_pointer + case_gen_i) == NULL) goto error; + _Py_UOpsSymType *seq; + _Py_UOpsSymType **values; + seq = stack_pointer[-1]; + values = &stack_pointer[-1]; + /* This has to be done manually */ + int totalargs = (oparg & 0xFF) + (oparg >> 8) + 1; + for (int i = 0; i < totalargs; i++) { + values[i] = sym_init_unknown(ctx); + if (values[i] == NULL) { + goto error; + } } stack_pointer += (oparg >> 8) + (oparg & 0xFF); break; } case _STORE_ATTR: { + _Py_UOpsSymType *owner; + _Py_UOpsSymType *v; + owner = stack_pointer[-1]; + v = stack_pointer[-2]; stack_pointer += -2; break; } case _DELETE_ATTR: { + _Py_UOpsSymType *owner; + owner = stack_pointer[-1]; stack_pointer += -1; break; } case _STORE_GLOBAL: { + _Py_UOpsSymType *v; + v = stack_pointer[-1]; stack_pointer += -1; break; } @@ -732,40 +674,43 @@ } case _LOAD_LOCALS: { - _Py_UOpsSymType *__locals_; - __locals_ = sym_init_unknown(ctx); - if(__locals_ == NULL) goto error; - stack_pointer[0] = __locals_; + _Py_UOpsSymType *locals; + locals = sym_init_unknown(ctx); + if (locals == NULL) goto error; + stack_pointer[0] = locals; stack_pointer += 1; break; } case _LOAD_FROM_DICT_OR_GLOBALS: { - _Py_UOpsSymType *__v_; - __v_ = sym_init_unknown(ctx); - if(__v_ == NULL) goto error; - stack_pointer[-1] = __v_; + _Py_UOpsSymType *mod_or_class_dict; + _Py_UOpsSymType *v; + mod_or_class_dict = stack_pointer[-1]; + v = sym_init_unknown(ctx); + if (v == NULL) goto error; + stack_pointer[-1] = v; break; } case _LOAD_NAME: { - _Py_UOpsSymType *__v_; - __v_ = sym_init_unknown(ctx); - if(__v_ == NULL) goto error; - stack_pointer[0] = __v_; + _Py_UOpsSymType *v; + v = sym_init_unknown(ctx); + if (v == NULL) goto error; + stack_pointer[0] = v; stack_pointer += 1; break; } case _LOAD_GLOBAL: { - _Py_UOpsSymType *__res_; - _Py_UOpsSymType *__null_ = NULL; - __null_ = sym_init_push_null(ctx); - if (__null_ == NULL) { goto error; } - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[0] = __res_; - if (oparg & 1) stack_pointer[1] = __null_; + _Py_UOpsSymType *res; + _Py_UOpsSymType *null = sym_init_null(ctx); + if(null) {goto error;} + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + null = sym_init_unknown(ctx); + if (null == NULL) goto error; + stack_pointer[0] = res; + if (oparg & 1) stack_pointer[1] = null; stack_pointer += 1 + (oparg & 1); break; } @@ -779,27 +724,29 @@ } case _LOAD_GLOBAL_MODULE: { - _Py_UOpsSymType *__res_; - _Py_UOpsSymType *__null_ = NULL; - __null_ = sym_init_push_null(ctx); - if (__null_ == NULL) { goto error; } - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[0] = __res_; - if (oparg & 1) stack_pointer[1] = __null_; + _Py_UOpsSymType *res; + _Py_UOpsSymType *null = sym_init_null(ctx); + if(null) {goto error;} + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + null = sym_init_unknown(ctx); + if (null == NULL) goto error; + stack_pointer[0] = res; + if (oparg & 1) stack_pointer[1] = null; stack_pointer += 1 + (oparg & 1); break; } case _LOAD_GLOBAL_BUILTINS: { - _Py_UOpsSymType *__res_; - _Py_UOpsSymType *__null_ = NULL; - __null_ = sym_init_push_null(ctx); - if (__null_ == NULL) { goto error; } - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[0] = __res_; - if (oparg & 1) stack_pointer[1] = __null_; + _Py_UOpsSymType *res; + _Py_UOpsSymType *null = sym_init_null(ctx); + if(null) {goto error;} + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + null = sym_init_unknown(ctx); + if (null == NULL) goto error; + stack_pointer[0] = res; + if (oparg & 1) stack_pointer[1] = null; stack_pointer += 1 + (oparg & 1); break; } @@ -817,23 +764,27 @@ } case _LOAD_FROM_DICT_OR_DEREF: { - _Py_UOpsSymType *__value_; - __value_ = sym_init_unknown(ctx); - if(__value_ == NULL) goto error; - stack_pointer[-1] = __value_; + _Py_UOpsSymType *class_dict; + _Py_UOpsSymType *value; + class_dict = stack_pointer[-1]; + value = sym_init_unknown(ctx); + if (value == NULL) goto error; + stack_pointer[-1] = value; break; } case _LOAD_DEREF: { - _Py_UOpsSymType *__value_; - __value_ = sym_init_unknown(ctx); - if(__value_ == NULL) goto error; - stack_pointer[0] = __value_; + _Py_UOpsSymType *value; + value = sym_init_unknown(ctx); + if (value == NULL) goto error; + stack_pointer[0] = value; stack_pointer += 1; break; } case _STORE_DEREF: { + _Py_UOpsSymType *v; + v = stack_pointer[-1]; stack_pointer += -1; break; } @@ -843,56 +794,70 @@ } case _BUILD_STRING: { - _Py_UOpsSymType *__str_; - __str_ = sym_init_unknown(ctx); - if(__str_ == NULL) goto error; - stack_pointer[-oparg] = __str_; + _Py_UOpsSymType **pieces; + _Py_UOpsSymType *str; + pieces = &stack_pointer[-oparg]; + str = sym_init_unknown(ctx); + if (str == NULL) goto error; + stack_pointer[-oparg] = str; stack_pointer += 1 - oparg; break; } case _BUILD_TUPLE: { - _Py_UOpsSymType *__tup_; - __tup_ = sym_init_unknown(ctx); - if(__tup_ == NULL) goto error; - stack_pointer[-oparg] = __tup_; + _Py_UOpsSymType **values; + _Py_UOpsSymType *tup; + values = &stack_pointer[-oparg]; + tup = sym_init_unknown(ctx); + if (tup == NULL) goto error; + stack_pointer[-oparg] = tup; stack_pointer += 1 - oparg; break; } case _BUILD_LIST: { - _Py_UOpsSymType *__list_; - __list_ = sym_init_unknown(ctx); - if(__list_ == NULL) goto error; - stack_pointer[-oparg] = __list_; + _Py_UOpsSymType **values; + _Py_UOpsSymType *list; + values = &stack_pointer[-oparg]; + list = sym_init_unknown(ctx); + if (list == NULL) goto error; + stack_pointer[-oparg] = list; stack_pointer += 1 - oparg; break; } case _LIST_EXTEND: { + _Py_UOpsSymType *iterable; + iterable = stack_pointer[-1]; stack_pointer += -1; break; } case _SET_UPDATE: { + _Py_UOpsSymType *iterable; + iterable = stack_pointer[-1]; stack_pointer += -1; break; } case _BUILD_SET: { - _Py_UOpsSymType *__set_; - __set_ = sym_init_unknown(ctx); - if(__set_ == NULL) goto error; - stack_pointer[-oparg] = __set_; + _Py_UOpsSymType **values; + _Py_UOpsSymType *set; + values = &stack_pointer[-oparg]; + set = sym_init_unknown(ctx); + if (set == NULL) goto error; + stack_pointer[-oparg] = set; stack_pointer += 1 - oparg; break; } case _BUILD_MAP: { - _Py_UOpsSymType *__map_; - __map_ = sym_init_unknown(ctx); - if(__map_ == NULL) goto error; - stack_pointer[-oparg*2] = __map_; + _Py_UOpsSymType **values; + _Py_UOpsSymType *map; + values = &stack_pointer[-oparg*2]; + map = sym_init_unknown(ctx); + if (map == NULL) goto error; + stack_pointer[-oparg*2] = map; stack_pointer += 1 - oparg*2; break; } @@ -902,25 +867,37 @@ } case _BUILD_CONST_KEY_MAP: { - _Py_UOpsSymType *__map_; - __map_ = sym_init_unknown(ctx); - if(__map_ == NULL) goto error; - stack_pointer[-1 - oparg] = __map_; + _Py_UOpsSymType *keys; + _Py_UOpsSymType **values; + _Py_UOpsSymType *map; + keys = stack_pointer[-1]; + values = &stack_pointer[-1 - oparg]; + map = sym_init_unknown(ctx); + if (map == NULL) goto error; + stack_pointer[-1 - oparg] = map; stack_pointer += -oparg; break; } case _DICT_UPDATE: { + _Py_UOpsSymType *update; + update = stack_pointer[-1]; stack_pointer += -1; break; } case _DICT_MERGE: { + _Py_UOpsSymType *update; + update = stack_pointer[-1]; stack_pointer += -1; break; } case _MAP_ADD: { + _Py_UOpsSymType *value; + _Py_UOpsSymType *key; + value = stack_pointer[-1]; + key = stack_pointer[-2]; stack_pointer += -2; break; } @@ -928,67 +905,61 @@ /* _INSTRUMENTED_LOAD_SUPER_ATTR is not a viable micro-op for tier 2 */ case _LOAD_SUPER_ATTR_ATTR: { - _Py_UOpsSymType *__attr_; - __attr_ = sym_init_unknown(ctx); - if(__attr_ == NULL) goto error; - stack_pointer[-3] = __attr_; + _Py_UOpsSymType *self; + _Py_UOpsSymType *class; + _Py_UOpsSymType *global_super; + _Py_UOpsSymType *attr; + self = stack_pointer[-1]; + class = stack_pointer[-2]; + global_super = stack_pointer[-3]; + attr = sym_init_unknown(ctx); + if (attr == NULL) goto error; + stack_pointer[-3] = attr; stack_pointer += -2 + ((0) ? 1 : 0); break; } case _LOAD_SUPER_ATTR_METHOD: { - _Py_UOpsSymType *__attr_; - _Py_UOpsSymType *__self_or_null_; - __attr_ = sym_init_unknown(ctx); - if(__attr_ == NULL) goto error; - __self_or_null_ = sym_init_unknown(ctx); - if(__self_or_null_ == NULL) goto error; - stack_pointer[-3] = __attr_; - stack_pointer[-2] = __self_or_null_; + _Py_UOpsSymType *self; + _Py_UOpsSymType *class; + _Py_UOpsSymType *global_super; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *self_or_null; + self = stack_pointer[-1]; + class = stack_pointer[-2]; + global_super = stack_pointer[-3]; + attr = sym_init_unknown(ctx); + if (attr == NULL) goto error; + self_or_null = sym_init_unknown(ctx); + if (self_or_null == NULL) goto error; + stack_pointer[-3] = attr; + stack_pointer[-2] = self_or_null; stack_pointer += -1; break; } case _LOAD_ATTR: { - _Py_UOpsSymType *__attr_; - _Py_UOpsSymType *__self_or_null_ = NULL; - __attr_ = sym_init_unknown(ctx); - if(__attr_ == NULL) goto error; - __self_or_null_ = sym_init_unknown(ctx); - if(__self_or_null_ == NULL) goto error; - sym_set_type(__self_or_null_, SELF_OR_NULL, 0); - stack_pointer[-1] = __attr_; - if (oparg & 1) stack_pointer[0] = __self_or_null_; + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *self_or_null = sym_init_null(ctx); + if(self_or_null) {goto error;} + owner = stack_pointer[-1]; + attr = sym_init_unknown(ctx); + if (attr == NULL) goto error; + self_or_null = sym_init_unknown(ctx); + if (self_or_null == NULL) goto error; + sym_set_type(self_or_null, SELF_OR_NULL, 0); + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = self_or_null; stack_pointer += (oparg & 1); break; } case _GUARD_TYPE_VERSION: { - _Py_UOpsSymType *__owner_; - __owner_ = stack_pointer[-1]; - // Constant evaluation - uint32_t type_version = (uint32_t)CURRENT_OPERAND(); - if (is_const(__owner_)) { - PyObject *owner; - owner = get_const(__owner_); - PyTypeObject *tp = Py_TYPE(owner); - assert(type_version != 0); - if (tp->tp_version_tag != type_version) goto error; - - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } - // Type guard elimination - if (sym_matches_type((_Py_UOpsSymType *)__owner_, GUARD_TYPE_VERSION_TYPE, (uint32_t)type_version)) { - DPRINTF(2, "type propagation eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } - else { - // Type propagation - sym_set_type((_Py_UOpsSymType *)__owner_, GUARD_TYPE_VERSION_TYPE, (uint32_t)type_version); - } + _Py_UOpsSymType *owner; + owner = stack_pointer[-1]; + uint32_t type_version = (uint32_t)inst->operand; + sym_set_type(owner, GUARD_TYPE_VERSION_TYPE, type_version); break; } @@ -997,125 +968,93 @@ } case _LOAD_ATTR_INSTANCE_VALUE: { - _Py_UOpsSymType *__attr_; - _Py_UOpsSymType *__null_ = NULL; - __null_ = sym_init_push_null(ctx); - if (__null_ == NULL) { goto error; } - __attr_ = sym_init_unknown(ctx); - if(__attr_ == NULL) goto error; - stack_pointer[-1] = __attr_; - if (oparg & 1) stack_pointer[0] = __null_; + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *null = sym_init_null(ctx); + if(null) {goto error;} + owner = stack_pointer[-1]; + attr = sym_init_unknown(ctx); + if (attr == NULL) goto error; + null = sym_init_unknown(ctx); + if (null == NULL) goto error; + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; stack_pointer += (oparg & 1); break; } case _CHECK_ATTR_MODULE: { - _Py_UOpsSymType *__owner_; - __owner_ = stack_pointer[-1]; - // Constant evaluation - uint32_t type_version = (uint32_t)CURRENT_OPERAND(); - if (is_const(__owner_)) { - PyObject *owner; - owner = get_const(__owner_); - if (!PyModule_CheckExact(owner)) goto error; - PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; - assert(dict != NULL); - if (dict->ma_keys->dk_version != type_version) goto error; - - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } break; } case _LOAD_ATTR_MODULE: { - _Py_UOpsSymType *__attr_; - _Py_UOpsSymType *__null_ = NULL; - __null_ = sym_init_push_null(ctx); - if (__null_ == NULL) { goto error; } - __attr_ = sym_init_unknown(ctx); - if(__attr_ == NULL) goto error; - stack_pointer[-1] = __attr_; - if (oparg & 1) stack_pointer[0] = __null_; + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *null = sym_init_null(ctx); + if(null) {goto error;} + owner = stack_pointer[-1]; + attr = sym_init_unknown(ctx); + if (attr == NULL) goto error; + null = sym_init_unknown(ctx); + if (null == NULL) goto error; + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; stack_pointer += (oparg & 1); break; } case _CHECK_ATTR_WITH_HINT: { - _Py_UOpsSymType *__owner_; - __owner_ = stack_pointer[-1]; - // Constant evaluation - if (is_const(__owner_)) { - PyObject *owner; - owner = get_const(__owner_); - assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); - if (_PyDictOrValues_IsValues(dorv)) goto error; - PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); - if (dict == NULL) goto error; - assert(PyDict_CheckExact((PyObject *)dict)); - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } break; } case _LOAD_ATTR_WITH_HINT: { - _Py_UOpsSymType *__attr_; - _Py_UOpsSymType *__null_ = NULL; - __null_ = sym_init_push_null(ctx); - if (__null_ == NULL) { goto error; } - __attr_ = sym_init_unknown(ctx); - if(__attr_ == NULL) goto error; - stack_pointer[-1] = __attr_; - if (oparg & 1) stack_pointer[0] = __null_; + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *null = sym_init_null(ctx); + if(null) {goto error;} + owner = stack_pointer[-1]; + attr = sym_init_unknown(ctx); + if (attr == NULL) goto error; + null = sym_init_unknown(ctx); + if (null == NULL) goto error; + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; stack_pointer += (oparg & 1); break; } case _LOAD_ATTR_SLOT: { - _Py_UOpsSymType *__attr_; - _Py_UOpsSymType *__null_ = NULL; - __null_ = sym_init_push_null(ctx); - if (__null_ == NULL) { goto error; } - __attr_ = sym_init_unknown(ctx); - if(__attr_ == NULL) goto error; - stack_pointer[-1] = __attr_; - if (oparg & 1) stack_pointer[0] = __null_; + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *null = sym_init_null(ctx); + if(null) {goto error;} + owner = stack_pointer[-1]; + attr = sym_init_unknown(ctx); + if (attr == NULL) goto error; + null = sym_init_unknown(ctx); + if (null == NULL) goto error; + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; stack_pointer += (oparg & 1); break; } case _CHECK_ATTR_CLASS: { - _Py_UOpsSymType *__owner_; - __owner_ = stack_pointer[-1]; - // Constant evaluation - uint32_t type_version = (uint32_t)CURRENT_OPERAND(); - if (is_const(__owner_)) { - PyObject *owner; - owner = get_const(__owner_); - if (!PyType_Check(owner)) goto error; - assert(type_version != 0); - if (((PyTypeObject *)owner)->tp_version_tag != type_version) goto error; - - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } break; } case _LOAD_ATTR_CLASS: { - _Py_UOpsSymType *__attr_; - _Py_UOpsSymType *__null_ = NULL; - __null_ = sym_init_push_null(ctx); - if (__null_ == NULL) { goto error; } - __attr_ = sym_init_unknown(ctx); - if(__attr_ == NULL) goto error; - stack_pointer[-1] = __attr_; - if (oparg & 1) stack_pointer[0] = __null_; + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *null = sym_init_null(ctx); + if(null) {goto error;} + owner = stack_pointer[-1]; + attr = sym_init_unknown(ctx); + if (attr == NULL) goto error; + null = sym_init_unknown(ctx); + if (null == NULL) goto error; + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; stack_pointer += (oparg & 1); break; } @@ -1125,34 +1064,17 @@ /* _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN is not a viable micro-op for tier 2 */ case _GUARD_DORV_VALUES: { - _Py_UOpsSymType *__owner_; - __owner_ = stack_pointer[-1]; - // Constant evaluation - if (is_const(__owner_)) { - PyObject *owner; - owner = get_const(__owner_); - assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); - if (!_PyDictOrValues_IsValues(dorv)) goto error; - - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } - // Type guard elimination - if (sym_matches_type((_Py_UOpsSymType *)__owner_, GUARD_DORV_VALUES_TYPE, (uint32_t)0)) { - DPRINTF(2, "type propagation eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } - else { - // Type propagation - sym_set_type((_Py_UOpsSymType *)__owner_, GUARD_DORV_VALUES_TYPE, (uint32_t)0); - } + _Py_UOpsSymType *owner; + owner = stack_pointer[-1]; + sym_set_type(owner, GUARD_DORV_VALUES_TYPE, 0); break; } case _STORE_ATTR_INSTANCE_VALUE: { + _Py_UOpsSymType *owner; + _Py_UOpsSymType *value; + owner = stack_pointer[-1]; + value = stack_pointer[-2]; stack_pointer += -2; break; } @@ -1160,81 +1082,115 @@ /* _STORE_ATTR_WITH_HINT is not a viable micro-op for tier 2 */ case _STORE_ATTR_SLOT: { + _Py_UOpsSymType *owner; + _Py_UOpsSymType *value; + owner = stack_pointer[-1]; + value = stack_pointer[-2]; stack_pointer += -2; break; } case _COMPARE_OP: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2] = __res_; + _Py_UOpsSymType *right; + _Py_UOpsSymType *left; + _Py_UOpsSymType *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2] = res; stack_pointer += -1; break; } case _COMPARE_OP_FLOAT: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2] = __res_; + _Py_UOpsSymType *right; + _Py_UOpsSymType *left; + _Py_UOpsSymType *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2] = res; stack_pointer += -1; break; } case _COMPARE_OP_INT: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2] = __res_; + _Py_UOpsSymType *right; + _Py_UOpsSymType *left; + _Py_UOpsSymType *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2] = res; stack_pointer += -1; break; } case _COMPARE_OP_STR: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2] = __res_; + _Py_UOpsSymType *right; + _Py_UOpsSymType *left; + _Py_UOpsSymType *res; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2] = res; stack_pointer += -1; break; } case _IS_OP: { - _Py_UOpsSymType *__b_; - __b_ = sym_init_unknown(ctx); - if(__b_ == NULL) goto error; - stack_pointer[-2] = __b_; + _Py_UOpsSymType *right; + _Py_UOpsSymType *left; + _Py_UOpsSymType *b; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + b = sym_init_unknown(ctx); + if (b == NULL) goto error; + stack_pointer[-2] = b; stack_pointer += -1; break; } case _CONTAINS_OP: { - _Py_UOpsSymType *__b_; - __b_ = sym_init_unknown(ctx); - if(__b_ == NULL) goto error; - stack_pointer[-2] = __b_; + _Py_UOpsSymType *right; + _Py_UOpsSymType *left; + _Py_UOpsSymType *b; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + b = sym_init_unknown(ctx); + if (b == NULL) goto error; + stack_pointer[-2] = b; stack_pointer += -1; break; } case _CHECK_EG_MATCH: { - _Py_UOpsSymType *__rest_; - _Py_UOpsSymType *__match_; - __rest_ = sym_init_unknown(ctx); - if(__rest_ == NULL) goto error; - __match_ = sym_init_unknown(ctx); - if(__match_ == NULL) goto error; - stack_pointer[-2] = __rest_; - stack_pointer[-1] = __match_; + _Py_UOpsSymType *match_type; + _Py_UOpsSymType *exc_value; + _Py_UOpsSymType *rest; + _Py_UOpsSymType *match; + match_type = stack_pointer[-1]; + exc_value = stack_pointer[-2]; + rest = sym_init_unknown(ctx); + if (rest == NULL) goto error; + match = sym_init_unknown(ctx); + if (match == NULL) goto error; + stack_pointer[-2] = rest; + stack_pointer[-1] = match; break; } case _CHECK_EXC_MATCH: { - _Py_UOpsSymType *__b_; - __b_ = sym_init_unknown(ctx); - if(__b_ == NULL) goto error; - stack_pointer[-1] = __b_; + _Py_UOpsSymType *right; + _Py_UOpsSymType *b; + right = stack_pointer[-1]; + b = sym_init_unknown(ctx); + if (b == NULL) goto error; + stack_pointer[-1] = b; break; } @@ -1245,81 +1201,93 @@ /* _POP_JUMP_IF_TRUE is not a viable micro-op for tier 2 */ case _IS_NONE: { - _Py_UOpsSymType *__b_; - __b_ = sym_init_unknown(ctx); - if(__b_ == NULL) goto error; - stack_pointer[-1] = __b_; + _Py_UOpsSymType *value; + _Py_UOpsSymType *b; + value = stack_pointer[-1]; + b = sym_init_unknown(ctx); + if (b == NULL) goto error; + stack_pointer[-1] = b; break; } case _GET_LEN: { - _Py_UOpsSymType *__len_o_; - __len_o_ = sym_init_unknown(ctx); - if(__len_o_ == NULL) goto error; - stack_pointer[0] = __len_o_; + _Py_UOpsSymType *len_o; + len_o = sym_init_unknown(ctx); + if (len_o == NULL) goto error; + stack_pointer[0] = len_o; stack_pointer += 1; break; } case _MATCH_CLASS: { - _Py_UOpsSymType *__attrs_; - __attrs_ = sym_init_unknown(ctx); - if(__attrs_ == NULL) goto error; - stack_pointer[-3] = __attrs_; + _Py_UOpsSymType *names; + _Py_UOpsSymType *type; + _Py_UOpsSymType *subject; + _Py_UOpsSymType *attrs; + names = stack_pointer[-1]; + type = stack_pointer[-2]; + subject = stack_pointer[-3]; + attrs = sym_init_unknown(ctx); + if (attrs == NULL) goto error; + stack_pointer[-3] = attrs; stack_pointer += -2; break; } case _MATCH_MAPPING: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[0] = __res_; + _Py_UOpsSymType *res; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[0] = res; stack_pointer += 1; break; } case _MATCH_SEQUENCE: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[0] = __res_; + _Py_UOpsSymType *res; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[0] = res; stack_pointer += 1; break; } case _MATCH_KEYS: { - _Py_UOpsSymType *__values_or_none_; - __values_or_none_ = sym_init_unknown(ctx); - if(__values_or_none_ == NULL) goto error; - stack_pointer[0] = __values_or_none_; + _Py_UOpsSymType *values_or_none; + values_or_none = sym_init_unknown(ctx); + if (values_or_none == NULL) goto error; + stack_pointer[0] = values_or_none; stack_pointer += 1; break; } case _GET_ITER: { - _Py_UOpsSymType *__iter_; - __iter_ = sym_init_unknown(ctx); - if(__iter_ == NULL) goto error; - stack_pointer[-1] = __iter_; + _Py_UOpsSymType *iterable; + _Py_UOpsSymType *iter; + iterable = stack_pointer[-1]; + iter = sym_init_unknown(ctx); + if (iter == NULL) goto error; + stack_pointer[-1] = iter; break; } case _GET_YIELD_FROM_ITER: { - _Py_UOpsSymType *__iter_; - __iter_ = sym_init_unknown(ctx); - if(__iter_ == NULL) goto error; - stack_pointer[-1] = __iter_; + _Py_UOpsSymType *iterable; + _Py_UOpsSymType *iter; + iterable = stack_pointer[-1]; + iter = sym_init_unknown(ctx); + if (iter == NULL) goto error; + stack_pointer[-1] = iter; break; } /* _FOR_ITER is not a viable micro-op for tier 2 */ case _FOR_ITER_TIER_TWO: { - _Py_UOpsSymType *__next_; - __next_ = sym_init_unknown(ctx); - if(__next_ == NULL) goto error; - stack_pointer[0] = __next_; + _Py_UOpsSymType *next; + next = sym_init_unknown(ctx); + if (next == NULL) goto error; + stack_pointer[0] = next; stack_pointer += 1; break; } @@ -1327,142 +1295,61 @@ /* _INSTRUMENTED_FOR_ITER is not a viable micro-op for tier 2 */ case _ITER_CHECK_LIST: { - _Py_UOpsSymType *__iter_; - __iter_ = stack_pointer[-1]; - // Constant evaluation - if (is_const(__iter_)) { - PyObject *iter; - iter = get_const(__iter_); - if (Py_TYPE(iter) != &PyListIter_Type) goto error; - - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } break; } /* _ITER_JUMP_LIST is not a viable micro-op for tier 2 */ case _GUARD_NOT_EXHAUSTED_LIST: { - _Py_UOpsSymType *__iter_; - __iter_ = stack_pointer[-1]; - // Constant evaluation - if (is_const(__iter_)) { - PyObject *iter; - iter = get_const(__iter_); - _PyListIterObject *it = (_PyListIterObject *)iter; - assert(Py_TYPE(iter) == &PyListIter_Type); - PyListObject *seq = it->it_seq; - if (seq == NULL) goto error; - if (it->it_index >= PyList_GET_SIZE(seq)) goto error; - - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } break; } case _ITER_NEXT_LIST: { - _Py_UOpsSymType *__next_; - __next_ = sym_init_unknown(ctx); - if(__next_ == NULL) goto error; - stack_pointer[0] = __next_; + _Py_UOpsSymType *next; + next = sym_init_unknown(ctx); + if (next == NULL) goto error; + stack_pointer[0] = next; stack_pointer += 1; break; } case _ITER_CHECK_TUPLE: { - _Py_UOpsSymType *__iter_; - __iter_ = stack_pointer[-1]; - // Constant evaluation - if (is_const(__iter_)) { - PyObject *iter; - iter = get_const(__iter_); - if (Py_TYPE(iter) != &PyTupleIter_Type) goto error; - - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } break; } /* _ITER_JUMP_TUPLE is not a viable micro-op for tier 2 */ case _GUARD_NOT_EXHAUSTED_TUPLE: { - _Py_UOpsSymType *__iter_; - __iter_ = stack_pointer[-1]; - // Constant evaluation - if (is_const(__iter_)) { - PyObject *iter; - iter = get_const(__iter_); - _PyTupleIterObject *it = (_PyTupleIterObject *)iter; - assert(Py_TYPE(iter) == &PyTupleIter_Type); - PyTupleObject *seq = it->it_seq; - if (seq == NULL) goto error; - if (it->it_index >= PyTuple_GET_SIZE(seq)) goto error; - - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } break; } case _ITER_NEXT_TUPLE: { - _Py_UOpsSymType *__next_; - __next_ = sym_init_unknown(ctx); - if(__next_ == NULL) goto error; - stack_pointer[0] = __next_; + _Py_UOpsSymType *next; + next = sym_init_unknown(ctx); + if (next == NULL) goto error; + stack_pointer[0] = next; stack_pointer += 1; break; } case _ITER_CHECK_RANGE: { - _Py_UOpsSymType *__iter_; - __iter_ = stack_pointer[-1]; - // Constant evaluation - if (is_const(__iter_)) { - PyObject *iter; - iter = get_const(__iter_); - _PyRangeIterObject *r = (_PyRangeIterObject *)iter; - if (Py_TYPE(r) != &PyRangeIter_Type) goto error; - - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } break; } /* _ITER_JUMP_RANGE is not a viable micro-op for tier 2 */ case _GUARD_NOT_EXHAUSTED_RANGE: { - _Py_UOpsSymType *__iter_; - __iter_ = stack_pointer[-1]; - // Constant evaluation - if (is_const(__iter_)) { - PyObject *iter; - iter = get_const(__iter_); - _PyRangeIterObject *r = (_PyRangeIterObject *)iter; - assert(Py_TYPE(r) == &PyRangeIter_Type); - if (r->len <= 0) goto error; - - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } break; } case _ITER_NEXT_RANGE: { - _Py_UOpsSymType *__next_; - __next_ = sym_init_unknown(ctx); - if(__next_ == NULL) goto error; - sym_set_type(__next_, PYLONG_TYPE, 0); - stack_pointer[0] = __next_; + _Py_UOpsSymType *iter; + _Py_UOpsSymType *next; + iter = stack_pointer[-1]; + next = sym_init_unknown(ctx); + if (next == NULL) goto error; + sym_set_type(next, PYLONG_TYPE, 0); + stack_pointer[0] = next; stack_pointer += 1; break; } @@ -1470,173 +1357,140 @@ /* _FOR_ITER_GEN is not a viable micro-op for tier 2 */ case _BEFORE_ASYNC_WITH: { - _Py_UOpsSymType *__exit_; - _Py_UOpsSymType *__res_; - __exit_ = sym_init_unknown(ctx); - if(__exit_ == NULL) goto error; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-1] = __exit_; - stack_pointer[0] = __res_; + _Py_UOpsSymType *mgr; + _Py_UOpsSymType *exit; + _Py_UOpsSymType *res; + mgr = stack_pointer[-1]; + exit = sym_init_unknown(ctx); + if (exit == NULL) goto error; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-1] = exit; + stack_pointer[0] = res; stack_pointer += 1; break; } case _BEFORE_WITH: { - _Py_UOpsSymType *__exit_; - _Py_UOpsSymType *__res_; - __exit_ = sym_init_unknown(ctx); - if(__exit_ == NULL) goto error; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-1] = __exit_; - stack_pointer[0] = __res_; + _Py_UOpsSymType *mgr; + _Py_UOpsSymType *exit; + _Py_UOpsSymType *res; + mgr = stack_pointer[-1]; + exit = sym_init_unknown(ctx); + if (exit == NULL) goto error; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-1] = exit; + stack_pointer[0] = res; stack_pointer += 1; break; } case _WITH_EXCEPT_START: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[0] = __res_; + _Py_UOpsSymType *res; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[0] = res; stack_pointer += 1; break; } case _PUSH_EXC_INFO: { - _Py_UOpsSymType *__prev_exc_; - _Py_UOpsSymType *__new_exc_; - __prev_exc_ = sym_init_unknown(ctx); - if(__prev_exc_ == NULL) goto error; - __new_exc_ = sym_init_unknown(ctx); - if(__new_exc_ == NULL) goto error; - stack_pointer[-1] = __prev_exc_; - stack_pointer[0] = __new_exc_; + _Py_UOpsSymType *new_exc; + _Py_UOpsSymType *prev_exc; + new_exc = stack_pointer[-1]; + prev_exc = sym_init_unknown(ctx); + if (prev_exc == NULL) goto error; + new_exc = sym_init_unknown(ctx); + if (new_exc == NULL) goto error; + stack_pointer[-1] = prev_exc; + stack_pointer[0] = new_exc; stack_pointer += 1; break; } case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT: { - _Py_UOpsSymType *__owner_; - __owner_ = stack_pointer[-1]; - // Constant evaluation - if (is_const(__owner_)) { - PyObject *owner; - owner = get_const(__owner_); - assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner); - if (!_PyDictOrValues_IsValues(*dorv) && !_PyObject_MakeInstanceAttributesFromDict(owner, dorv)) goto error; - - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } break; } case _GUARD_KEYS_VERSION: { - _Py_UOpsSymType *__owner_; - __owner_ = stack_pointer[-1]; - // Constant evaluation - uint32_t keys_version = (uint32_t)CURRENT_OPERAND(); - if (is_const(__owner_)) { - PyObject *owner; - owner = get_const(__owner_); - PyTypeObject *owner_cls = Py_TYPE(owner); - PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; - if (owner_heap_type->ht_cached_keys->dk_version != keys_version) goto error; - - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } - // Type guard elimination - if (sym_matches_type((_Py_UOpsSymType *)__owner_, GUARD_KEYS_VERSION_TYPE, (uint32_t)keys_version)) { - DPRINTF(2, "type propagation eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } - else { - // Type propagation - sym_set_type((_Py_UOpsSymType *)__owner_, GUARD_KEYS_VERSION_TYPE, (uint32_t)keys_version); - } + _Py_UOpsSymType *owner; + owner = stack_pointer[-1]; + uint32_t keys_version = (uint32_t)inst->operand; + sym_set_type(owner, GUARD_KEYS_VERSION_TYPE, keys_version); break; } case _LOAD_ATTR_METHOD_WITH_VALUES: { - _Py_UOpsSymType *__attr_; - _Py_UOpsSymType *__self_ = NULL; - __attr_ = sym_init_unknown(ctx); - if(__attr_ == NULL) goto error; - __self_ = sym_init_unknown(ctx); - if(__self_ == NULL) goto error; - stack_pointer[-1] = __attr_; - if (1) stack_pointer[0] = __self_; + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *self = sym_init_null(ctx); + if(self) {goto error;} + owner = stack_pointer[-1]; + attr = sym_init_unknown(ctx); + if (attr == NULL) goto error; + self = sym_init_unknown(ctx); + if (self == NULL) goto error; + stack_pointer[-1] = attr; + if (1) stack_pointer[0] = self; stack_pointer += ((1) ? 1 : 0); break; } case _LOAD_ATTR_METHOD_NO_DICT: { - _Py_UOpsSymType *__attr_; - _Py_UOpsSymType *__self_ = NULL; - __attr_ = sym_init_unknown(ctx); - if(__attr_ == NULL) goto error; - __self_ = sym_init_unknown(ctx); - if(__self_ == NULL) goto error; - stack_pointer[-1] = __attr_; - if (1) stack_pointer[0] = __self_; + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *self = sym_init_null(ctx); + if(self) {goto error;} + owner = stack_pointer[-1]; + attr = sym_init_unknown(ctx); + if (attr == NULL) goto error; + self = sym_init_unknown(ctx); + if (self == NULL) goto error; + stack_pointer[-1] = attr; + if (1) stack_pointer[0] = self; stack_pointer += ((1) ? 1 : 0); break; } case _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: { - _Py_UOpsSymType *__attr_; - __attr_ = sym_init_unknown(ctx); - if(__attr_ == NULL) goto error; - stack_pointer[-1] = __attr_; + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + owner = stack_pointer[-1]; + attr = sym_init_unknown(ctx); + if (attr == NULL) goto error; + stack_pointer[-1] = attr; stack_pointer += ((0) ? 1 : 0); break; } case _LOAD_ATTR_NONDESCRIPTOR_NO_DICT: { - _Py_UOpsSymType *__attr_; - __attr_ = sym_init_unknown(ctx); - if(__attr_ == NULL) goto error; - stack_pointer[-1] = __attr_; + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + owner = stack_pointer[-1]; + attr = sym_init_unknown(ctx); + if (attr == NULL) goto error; + stack_pointer[-1] = attr; stack_pointer += ((0) ? 1 : 0); break; } case _CHECK_ATTR_METHOD_LAZY_DICT: { - _Py_UOpsSymType *__owner_; - __owner_ = stack_pointer[-1]; - // Constant evaluation - if (is_const(__owner_)) { - PyObject *owner; - owner = get_const(__owner_); - Py_ssize_t dictoffset = Py_TYPE(owner)->tp_dictoffset; - assert(dictoffset > 0); - PyObject *dict = *(PyObject **)((char *)owner + dictoffset); - /* This object has a __dict__, just not yet created */ - if (dict != NULL) goto error; - - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } break; } case _LOAD_ATTR_METHOD_LAZY_DICT: { - _Py_UOpsSymType *__attr_; - _Py_UOpsSymType *__self_ = NULL; - __attr_ = sym_init_unknown(ctx); - if(__attr_ == NULL) goto error; - __self_ = sym_init_unknown(ctx); - if(__self_ == NULL) goto error; - stack_pointer[-1] = __attr_; - if (1) stack_pointer[0] = __self_; + _Py_UOpsSymType *owner; + _Py_UOpsSymType *attr; + _Py_UOpsSymType *self = sym_init_null(ctx); + if(self) {goto error;} + owner = stack_pointer[-1]; + attr = sym_init_unknown(ctx); + if (attr == NULL) goto error; + self = sym_init_unknown(ctx); + if (self == NULL) goto error; + stack_pointer[-1] = attr; + if (1) stack_pointer[0] = self; stack_pointer += ((1) ? 1 : 0); break; } @@ -1646,113 +1500,148 @@ /* _CALL is not a viable micro-op for tier 2 */ case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: { - _Py_UOpsSymType *__null_; - _Py_UOpsSymType *__callable_; - __null_ = stack_pointer[-1 - oparg]; - __callable_ = stack_pointer[-2 - oparg]; - // Constant evaluation - if (is_const(__callable_) && is_const(__null_)) { - PyObject *null; - PyObject *callable; - callable = get_const(__callable_); - null = get_const(__null_); - if (null != NULL) goto error; - if (Py_TYPE(callable) != &PyMethod_Type) goto error; - - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } - // Type guard elimination - if (sym_matches_type((_Py_UOpsSymType *)__callable_, PYMETHOD_TYPE, (uint32_t)0) && sym_matches_type((_Py_UOpsSymType *)__null_, NULL_TYPE, (uint32_t)0)) { - DPRINTF(2, "type propagation eliminated guard\n"); - new_inst.opcode = _NOP; - break; - } - else { - // Type propagation - sym_set_type((_Py_UOpsSymType *)__callable_, PYMETHOD_TYPE, (uint32_t)0); - sym_set_type((_Py_UOpsSymType *)__null_, NULL_TYPE, (uint32_t)0); - } + _Py_UOpsSymType *null; + _Py_UOpsSymType *callable; + null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + sym_set_type(callable, PYMETHOD_TYPE, 0); + sym_set_type(null, NULL_TYPE, 0); break; } case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: { - _Py_UOpsSymType *__func_; - _Py_UOpsSymType *__self_; - __func_ = sym_init_unknown(ctx); - if(__func_ == NULL) goto error; - __self_ = sym_init_unknown(ctx); - if(__self_ == NULL) goto error; - stack_pointer[-2 - oparg] = __func_; - stack_pointer[-1 - oparg] = __self_; + _Py_UOpsSymType *callable; + _Py_UOpsSymType *func; + _Py_UOpsSymType *self; + callable = stack_pointer[-2]; + func = sym_init_unknown(ctx); + if (func == NULL) goto error; + self = sym_init_unknown(ctx); + if (self == NULL) goto error; + stack_pointer[-2] = func; + stack_pointer[-1] = self; + break; + } + + case _CHECK_PEP_523: { + /* Setting the eval frame function invalidates + * all executors, so no need to check dynamically */ + if (_PyInterpreterState_GET()->eval_frame == NULL) { + REPLACE_OP(_NOP, 0, 0); + } break; } case _CHECK_FUNCTION_EXACT_ARGS: { - _Py_UOpsSymType *__self_or_null_; - _Py_UOpsSymType *__callable_; - __self_or_null_ = stack_pointer[-1 - oparg]; - __callable_ = stack_pointer[-2 - oparg]; - // Constant evaluation - uint32_t func_version = (uint32_t)CURRENT_OPERAND(); - if (is_const(__callable_) && is_const(__self_or_null_)) { - PyObject *self_or_null; - PyObject *callable; - callable = get_const(__callable_); - self_or_null = get_const(__self_or_null_); - if (!PyFunction_Check(callable)) goto error; - PyFunctionObject *func = (PyFunctionObject *)callable; - if (func->func_version != func_version) goto error; - PyCodeObject *code = (PyCodeObject *)func->func_code; - if (code->co_argcount != oparg + (self_or_null != NULL)) goto error; - - DPRINTF(3, "const eliminated guard\n"); - new_inst.opcode = _NOP; - break; + _Py_UOpsSymType *self_or_null; + _Py_UOpsSymType *callable; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + uint32_t func_version = (uint32_t)inst->operand; + sym_set_type(callable, PYFUNCTION_TYPE_VERSION_TYPE, func_version); + break; + } + + case _CHECK_STACK_SPACE: { + break; + } + + case _INIT_CALL_PY_EXACT_ARGS: { + _Py_UOpsSymType **args; + _Py_UOpsSymType *self_or_null; + _Py_UOpsSymType *callable; + _Py_UOpsAbstractFrame *new_frame; + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + int argcount = oparg; + PyFunctionObject *func = extract_func_from_sym(callable); + if (func == NULL) { + goto error; + } + PyCodeObject *co = (PyCodeObject *)func->func_code; + assert(self_or_null != NULL); + assert(args != NULL); + if (!sym_is_type(self_or_null, NULL_TYPE) && + !sym_is_type(self_or_null, SELF_OR_NULL)) { + // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in + // VM + args--; + argcount++; } - // Type guard elimination - if (sym_matches_type((_Py_UOpsSymType *)__callable_, PYFUNCTION_TYPE_VERSION_TYPE, (uint32_t)func_version)) { - DPRINTF(2, "type propagation eliminated guard\n"); - new_inst.opcode = _NOP; - break; + _Py_UOpsSymType **localsplus_start = ctx->n_consumed; + int n_locals_already_filled = 0; + // Can determine statically, so we interleave the new locals + // and make the current stack the new locals. + // This also sets up for true call inlining. + if (!sym_is_type(self_or_null, SELF_OR_NULL)) { + localsplus_start = args; + n_locals_already_filled = argcount; } - else { - // Type propagation - sym_set_type((_Py_UOpsSymType *)__callable_, PYFUNCTION_TYPE_VERSION_TYPE, (uint32_t)func_version); + new_frame = ctx_frame_new(ctx, co, localsplus_start, n_locals_already_filled, 0); + if (new_frame == NULL){ + goto error; } + stack_pointer[-2 - oparg] = (PyObject *)new_frame; + stack_pointer += -1 - oparg; break; } - case _CHECK_STACK_SPACE: { + case _PUSH_FRAME: { + _Py_UOpsAbstractFrame *new_frame; + new_frame = (_Py_UOpsAbstractFrame *)stack_pointer[-1]; + stack_pointer += -1; + ctx->frame->stack_pointer = stack_pointer; + ctx->frame = new_frame; + ctx->curr_frame_depth++; + stack_pointer = new_frame->stack_pointer; + stack_pointer += ((0) ? 1 : 0); break; } /* _CALL_PY_WITH_DEFAULTS is not a viable micro-op for tier 2 */ case _CALL_TYPE_1: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2 - oparg] = __res_; + _Py_UOpsSymType **args; + _Py_UOpsSymType *null; + _Py_UOpsSymType *callable; + _Py_UOpsSymType *res; + args = &stack_pointer[-oparg]; + null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; } case _CALL_STR_1: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2 - oparg] = __res_; + _Py_UOpsSymType **args; + _Py_UOpsSymType *null; + _Py_UOpsSymType *callable; + _Py_UOpsSymType *res; + args = &stack_pointer[-oparg]; + null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; } case _CALL_TUPLE_1: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2 - oparg] = __res_; + _Py_UOpsSymType **args; + _Py_UOpsSymType *null; + _Py_UOpsSymType *callable; + _Py_UOpsSymType *res; + args = &stack_pointer[-oparg]; + null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; } @@ -1760,96 +1649,158 @@ /* _CALL_ALLOC_AND_ENTER_INIT is not a viable micro-op for tier 2 */ case _EXIT_INIT_CHECK: { + _Py_UOpsSymType *should_be_none; + should_be_none = stack_pointer[-1]; stack_pointer += -1; break; } case _CALL_BUILTIN_CLASS: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2 - oparg] = __res_; + _Py_UOpsSymType **args; + _Py_UOpsSymType *self_or_null; + _Py_UOpsSymType *callable; + _Py_UOpsSymType *res; + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; } case _CALL_BUILTIN_O: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2 - oparg] = __res_; + _Py_UOpsSymType **args; + _Py_UOpsSymType *self_or_null; + _Py_UOpsSymType *callable; + _Py_UOpsSymType *res; + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; } case _CALL_BUILTIN_FAST: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2 - oparg] = __res_; + _Py_UOpsSymType **args; + _Py_UOpsSymType *self_or_null; + _Py_UOpsSymType *callable; + _Py_UOpsSymType *res; + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; } case _CALL_BUILTIN_FAST_WITH_KEYWORDS: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2 - oparg] = __res_; + _Py_UOpsSymType **args; + _Py_UOpsSymType *self_or_null; + _Py_UOpsSymType *callable; + _Py_UOpsSymType *res; + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; } case _CALL_LEN: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2 - oparg] = __res_; + _Py_UOpsSymType **args; + _Py_UOpsSymType *self_or_null; + _Py_UOpsSymType *callable; + _Py_UOpsSymType *res; + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; } case _CALL_ISINSTANCE: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2 - oparg] = __res_; + _Py_UOpsSymType **args; + _Py_UOpsSymType *self_or_null; + _Py_UOpsSymType *callable; + _Py_UOpsSymType *res; + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; } case _CALL_METHOD_DESCRIPTOR_O: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2 - oparg] = __res_; + _Py_UOpsSymType **args; + _Py_UOpsSymType *self_or_null; + _Py_UOpsSymType *callable; + _Py_UOpsSymType *res; + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; } case _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2 - oparg] = __res_; + _Py_UOpsSymType **args; + _Py_UOpsSymType *self_or_null; + _Py_UOpsSymType *callable; + _Py_UOpsSymType *res; + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; } case _CALL_METHOD_DESCRIPTOR_NOARGS: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2 - oparg] = __res_; + _Py_UOpsSymType **args; + _Py_UOpsSymType *self_or_null; + _Py_UOpsSymType *callable; + _Py_UOpsSymType *res; + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; } case _CALL_METHOD_DESCRIPTOR_FAST: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2 - oparg] = __res_; + _Py_UOpsSymType **args; + _Py_UOpsSymType *self_or_null; + _Py_UOpsSymType *callable; + _Py_UOpsSymType *res; + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; } @@ -1863,74 +1814,107 @@ /* _CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ case _MAKE_FUNCTION: { - _Py_UOpsSymType *__func_; - __func_ = sym_init_unknown(ctx); - if(__func_ == NULL) goto error; - stack_pointer[-1] = __func_; + _Py_UOpsSymType *codeobj; + _Py_UOpsSymType *func; + codeobj = stack_pointer[-1]; + func = sym_init_unknown(ctx); + if (func == NULL) goto error; + stack_pointer[-1] = func; break; } case _SET_FUNCTION_ATTRIBUTE: { - _Py_UOpsSymType *__func_; - __func_ = sym_init_unknown(ctx); - if(__func_ == NULL) goto error; - stack_pointer[-2] = __func_; + _Py_UOpsSymType *func; + _Py_UOpsSymType *attr; + func = stack_pointer[-1]; + attr = stack_pointer[-2]; + func = sym_init_unknown(ctx); + if (func == NULL) goto error; + stack_pointer[-2] = func; stack_pointer += -1; break; } case _BUILD_SLICE: { - _Py_UOpsSymType *__slice_; - __slice_ = sym_init_unknown(ctx); - if(__slice_ == NULL) goto error; - stack_pointer[-2 - ((oparg == 3) ? 1 : 0)] = __slice_; + _Py_UOpsSymType *step = sym_init_null(ctx); + if(step) {goto error;} + _Py_UOpsSymType *stop; + _Py_UOpsSymType *start; + _Py_UOpsSymType *slice; + if (oparg == 3) { step = stack_pointer[-((oparg == 3) ? 1 : 0)]; } + stop = stack_pointer[-1 - ((oparg == 3) ? 1 : 0)]; + start = stack_pointer[-2 - ((oparg == 3) ? 1 : 0)]; + slice = sym_init_unknown(ctx); + if (slice == NULL) goto error; + stack_pointer[-2 - ((oparg == 3) ? 1 : 0)] = slice; stack_pointer += -1 - ((oparg == 3) ? 1 : 0); break; } case _CONVERT_VALUE: { - _Py_UOpsSymType *__result_; - __result_ = sym_init_unknown(ctx); - if(__result_ == NULL) goto error; - stack_pointer[-1] = __result_; + _Py_UOpsSymType *value; + _Py_UOpsSymType *result; + value = stack_pointer[-1]; + result = sym_init_unknown(ctx); + if (result == NULL) goto error; + stack_pointer[-1] = result; break; } case _FORMAT_SIMPLE: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-1] = __res_; + _Py_UOpsSymType *value; + _Py_UOpsSymType *res; + value = stack_pointer[-1]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-1] = res; break; } case _FORMAT_WITH_SPEC: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2] = __res_; + _Py_UOpsSymType *fmt_spec; + _Py_UOpsSymType *value; + _Py_UOpsSymType *res; + fmt_spec = stack_pointer[-1]; + value = stack_pointer[-2]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2] = res; stack_pointer += -1; break; } + case _COPY: { + _Py_UOpsSymType *bottom; + _Py_UOpsSymType *top; + bottom = stack_pointer[-1 - (oparg-1)]; + assert(oparg > 0); + top = bottom; + stack_pointer[0] = top; + stack_pointer += 1; + break; + } + case _BINARY_OP: { - _Py_UOpsSymType *__res_; - __res_ = sym_init_unknown(ctx); - if(__res_ == NULL) goto error; - stack_pointer[-2] = __res_; + _Py_UOpsSymType *rhs; + _Py_UOpsSymType *lhs; + _Py_UOpsSymType *res; + rhs = stack_pointer[-1]; + lhs = stack_pointer[-2]; + res = sym_init_unknown(ctx); + if (res == NULL) goto error; + stack_pointer[-2] = res; stack_pointer += -1; break; } case _SWAP: { - _Py_UOpsSymType *__top_; - _Py_UOpsSymType *__bottom_; - __top_ = stack_pointer[-1]; - __bottom_ = stack_pointer[-2 - (oparg-2)]; - (void)__bottom_; - (void)__top_; - stack_pointer[-2 - (oparg-2)] = __top_; - stack_pointer[-1] = __bottom_; + _Py_UOpsSymType *top; + _Py_UOpsSymType *bottom; + top = stack_pointer[-1]; + bottom = stack_pointer[-2 - (oparg-2)]; + stack_pointer[-2 - (oparg-2)] = top; + stack_pointer[-1] = bottom; break; } @@ -1949,21 +1933,29 @@ /* _INSTRUMENTED_POP_JUMP_IF_NOT_NONE is not a viable micro-op for tier 2 */ case _GUARD_IS_TRUE_POP: { + _Py_UOpsSymType *flag; + flag = stack_pointer[-1]; stack_pointer += -1; break; } case _GUARD_IS_FALSE_POP: { + _Py_UOpsSymType *flag; + flag = stack_pointer[-1]; stack_pointer += -1; break; } case _GUARD_IS_NONE_POP: { + _Py_UOpsSymType *val; + val = stack_pointer[-1]; stack_pointer += -1; break; } case _GUARD_IS_NOT_NONE_POP: { + _Py_UOpsSymType *val; + val = stack_pointer[-1]; stack_pointer += -1; break; } @@ -1972,6 +1964,14 @@ break; } + case _SET_IP: { + break; + } + + case _SAVE_RETURN_OFFSET: { + break; + } + case _EXIT_TRACE: { break; } @@ -1984,14 +1984,92 @@ break; } - case _INTERNAL_INCREMENT_OPT_COUNTER: { - stack_pointer += -1; + case _CHECK_VALIDITY: { break; } - case _SHRINK_STACK: { - stack_pointer += -oparg; + case _LOAD_CONST_INLINE: { + _Py_UOpsSymType *value; + PyObject *ptr = (PyObject *)inst->operand; + _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); + if (sym_const == NULL) { + goto error; + } + value = sym_const; + assert(is_const(value)); + stack_pointer[0] = value; + stack_pointer += 1; + break; + } + + case _LOAD_CONST_INLINE_BORROW: { + _Py_UOpsSymType *value; + PyObject *ptr = (PyObject *)inst->operand; + _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); + if (sym_const == NULL) { + goto error; + } + value = sym_const; + assert(is_const(value)); + stack_pointer[0] = value; + stack_pointer += 1; + break; + } + + case _LOAD_CONST_INLINE_WITH_NULL: { + _Py_UOpsSymType *value; + _Py_UOpsSymType *null; + PyObject *ptr = (PyObject *)inst->operand; + _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); + if (sym_const == NULL) { + goto error; + } + value = sym_const; + assert(is_const(value)); + _Py_UOpsSymType *null_sym = sym_init_null(ctx); + if (null_sym == NULL) { + goto error; + } + null = null_sym; + stack_pointer[0] = value; + stack_pointer[1] = null; + stack_pointer += 2; + break; + } + + case _LOAD_CONST_INLINE_BORROW_WITH_NULL: { + _Py_UOpsSymType *value; + _Py_UOpsSymType *null; + PyObject *ptr = (PyObject *)inst->operand; + _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); + if (sym_const == NULL) { + goto error; + } + value = sym_const; + assert(is_const(value)); + _Py_UOpsSymType *null_sym = sym_init_null(ctx); + if (null_sym == NULL) { + goto error; + } + null = null_sym; + stack_pointer[0] = value; + stack_pointer[1] = null; + stack_pointer += 2; + break; + } + + case _CHECK_GLOBALS: { + break; + } + + case _CHECK_BUILTINS: { + break; + } + + case _INTERNAL_INCREMENT_OPT_COUNTER: { + _Py_UOpsSymType *opt; + opt = stack_pointer[-1]; + stack_pointer += -1; break; } -#undef TIER_TWO diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 6e22f07b69ae2d..9d95ec3fce2885 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -411,12 +411,12 @@ dummy_func( // BINARY_OP_INPLACE_ADD_UNICODE, // See comments at that opcode. }; - op(_GUARD_BOTH_INT, (left, right -- left: &PYLONG_TYPE, right: &PYLONG_TYPE)) { + op(_GUARD_BOTH_INT, (left, right -- left, right)) { DEOPT_IF(!PyLong_CheckExact(left)); DEOPT_IF(!PyLong_CheckExact(right)); } - pure op(_BINARY_OP_MULTIPLY_INT, (left, right -- res: &PYLONG_TYPE)) { + pure 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); } - pure op(_BINARY_OP_ADD_INT, (left, right -- res: &PYLONG_TYPE)) { + pure 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); } - pure op(_BINARY_OP_SUBTRACT_INT, (left, right -- res: &PYLONG_TYPE)) { + pure 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); @@ -447,7 +447,7 @@ dummy_func( macro(BINARY_OP_SUBTRACT_INT) = _GUARD_BOTH_INT + unused/1 + _BINARY_OP_SUBTRACT_INT; - op(_GUARD_BOTH_FLOAT, (left, right -- left: &PYFLOAT_TYPE, right: &PYFLOAT_TYPE)) { + op(_GUARD_BOTH_FLOAT, (left, right -- left, right)) { DEOPT_IF(!PyFloat_CheckExact(left)); DEOPT_IF(!PyFloat_CheckExact(right)); } @@ -4116,10 +4116,6 @@ dummy_func( exe->count++; } - op(_SHRINK_STACK, (args[oparg] --)) { - DECREF_INPUTS(); - } - // END BYTECODES // diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index e9bec214860ac1..2f32b5275f42c8 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3470,15 +3470,4 @@ break; } - case _SHRINK_STACK: { - PyObject **args; - oparg = CURRENT_OPARG(); - args = &stack_pointer[-oparg]; - for (int _i = oparg; --_i >= 0;) { - Py_DECREF(args[_i]); - } - stack_pointer += -oparg; - break; - } - #undef TIER_TWO diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 774d956df0f516..42ab4abb61813d 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -183,8 +183,8 @@ create_sym_consts(_Py_UOpsAbstractInterpContext *ctx, PyObject *co_consts) static inline _Py_UOpsSymType* sym_init_unknown(_Py_UOpsAbstractInterpContext *ctx); // 0 on success, -1 on error. -static int -ctx_frame_push( +static _Py_UOpsAbstractFrame * +ctx_frame_new( _Py_UOpsAbstractInterpContext *ctx, PyCodeObject *co, _Py_UOpsSymType **localsplus_start, @@ -194,11 +194,10 @@ ctx_frame_push( { _Py_UOpsSymType **sym_consts = create_sym_consts(ctx, co->co_consts); if (sym_consts == NULL) { - return -1; + return NULL; } assert(ctx->curr_frame_depth < MAX_ABSTRACT_FRAME_DEPTH); _Py_UOpsAbstractFrame *frame = &ctx->frames[ctx->curr_frame_depth]; - ctx->curr_frame_depth++; frame->sym_consts = sym_consts; frame->sym_consts_len = (int)Py_SIZE(co->co_consts); @@ -210,7 +209,7 @@ ctx_frame_push( frame->stack_pointer = frame->stack + curr_stackentries; ctx->n_consumed = localsplus_start + (co->co_nlocalsplus + co->co_stacksize); if (ctx->n_consumed >= ctx->limit) { - return -1; + return NULL; } @@ -218,7 +217,7 @@ ctx_frame_push( for (int i = n_locals_already_filled; i < co->co_nlocalsplus; i++) { _Py_UOpsSymType *local = sym_init_unknown(ctx); if (local == NULL) { - return -1; + return NULL; } frame->locals[i] = local; } @@ -228,13 +227,12 @@ ctx_frame_push( for (int i = 0; i < curr_stackentries; i++) { _Py_UOpsSymType *stackvar = sym_init_unknown(ctx); if (stackvar == NULL) { - return -1; + return NULL; } frame->stack[i] = stackvar; } - ctx->frame = frame; - return 0; + return frame; } static void @@ -273,9 +271,12 @@ abstractcontext_init( // Frame setup ctx->curr_frame_depth = 0; - if (ctx_frame_push(ctx, co, ctx->n_consumed, 0, curr_stacklen) < 0) { + _Py_UOpsAbstractFrame *frame = ctx_frame_new(ctx, co, ctx->n_consumed, 0, curr_stacklen); + if (frame == NULL) { return -1; } + ctx->curr_frame_depth++; + ctx->frame = frame; // IR and sym setup ctx->frequent_syms.push_nulL_sym = NULL; @@ -437,7 +438,7 @@ sym_init_const(_Py_UOpsAbstractInterpContext *ctx, PyObject *const_val) } static _Py_UOpsSymType* -sym_init_push_null(_Py_UOpsAbstractInterpContext *ctx) +sym_init_null(_Py_UOpsAbstractInterpContext *ctx) { if (ctx->frequent_syms.push_nulL_sym != NULL) { return ctx->frequent_syms.push_nulL_sym; @@ -554,85 +555,8 @@ emit_i(uops_emitter *emitter, return 0; } -static inline bool -op_is_zappable(int opcode) -{ - switch(opcode) { - case _SET_IP: - case _CHECK_VALIDITY: - return true; - default: - return (_PyUop_Flags[opcode] & HAS_PURE_FLAG) && !((_PyUop_Flags[opcode] & HAS_DEOPT_FLAG)); - } -} -static inline int -emit_const(uops_emitter *emitter, - PyObject *const_val, - int num_pops) -{ - _PyUOpInstruction shrink_stack = {_SHRINK_STACK, num_pops, 0, 0}; - // If all that precedes a _SHRINK_STACK is a bunch of pure instructions, - // then we can safely eliminate that without side effects - int net_stack_effect = -num_pops; - _PyUOpInstruction *back = emitter->writebuffer + emitter->curr_i - 1; - while (back >= emitter->writebuffer && - op_is_zappable(back->opcode)) { - net_stack_effect += _PyUop_NetStackEffect(back->opcode, back->oparg); - back--; - if (net_stack_effect == 0) { - break; - } - } - if (net_stack_effect == 0) { - back = emitter->writebuffer + emitter->curr_i - 1; - net_stack_effect = -num_pops; - // Back up over the previous loads and zap them. - while(net_stack_effect != 0) { - net_stack_effect += _PyUop_NetStackEffect(back->opcode, back->oparg); - if (back->opcode == _LOAD_CONST_INLINE || - back->opcode == _LOAD_CONST_INLINE_WITH_NULL) { - PyObject *old_const_val = (PyObject *)back->operand; - Py_DECREF(old_const_val); - back->operand = (uintptr_t)NULL; - } - back->opcode = NOP; - back--; - } - } - else { - if (emit_i(emitter, shrink_stack) < 0) { - return -1; - } - } - int load_const_opcode = _Py_IsImmortal(const_val) - ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE; - if (load_const_opcode == _LOAD_CONST_INLINE) { - Py_INCREF(const_val); - } - _PyUOpInstruction load_const = {load_const_opcode, 0, 0, (uintptr_t)const_val}; - if (emit_i(emitter, load_const) < 0) { - return -1; - } - - return 0; -} - - -#define DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dval, result) \ -do { \ - { \ - result = PyFloat_FromDouble(dval); \ - if ((result) == NULL) goto error; \ - } \ -} while (0) - -#define DEOPT_IF(COND, INSTNAME) \ - if ((COND)) { \ - goto guard_required; \ - } - #ifndef Py_DEBUG #define GETITEM(ctx, i) (ctx->frame->sym_consts[(i)]) #else @@ -680,6 +604,11 @@ uop_abstract_interpret_single_inst( #define CURRENT_OPERAND() (operand) #define TIER_TWO_ONLY ((void)0) +#define REPLACE_OP(op, arg, oper) \ + new_inst.opcode = op; \ + new_inst.oparg = arg; \ + new_inst.operand = oper; + int oparg = inst->oparg; uint32_t opcode = inst->opcode; @@ -693,195 +622,6 @@ uop_abstract_interpret_single_inst( oparg); switch (opcode) { #include "abstract_interp_cases.c.h" - // Note: LOAD_FAST_CHECK is not pure!!! - case LOAD_FAST_CHECK: { - STACK_GROW(1); - _Py_UOpsSymType *local = GETLOCAL(oparg); - // We guarantee this will error - just bail and don't optimize it. - if (sym_is_type(local, NULL_TYPE)) { - goto error; - } - PEEK(1) = local; - break; - } - case LOAD_FAST: { - STACK_GROW(1); - _Py_UOpsSymType * local = GETLOCAL(oparg); - if (sym_is_type(local, NULL_TYPE)) { - Py_UNREACHABLE(); - } - // Guaranteed by the CPython bytecode compiler to not be uninitialized. - PEEK(1) = GETLOCAL(oparg); - assert(PEEK(1)); - - break; - } - case LOAD_FAST_AND_CLEAR: { - STACK_GROW(1); - PEEK(1) = GETLOCAL(oparg); - break; - } - case LOAD_CONST: { - STACK_GROW(1); - PEEK(1) = (_Py_UOpsSymType *)GETITEM( - ctx, oparg); - assert(is_const(PEEK(1))); - // Peephole: inline constants. - PyObject *val = get_const_borrow(PEEK(1)); - new_inst.opcode = _Py_IsImmortal(val) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE; - if (new_inst.opcode == _LOAD_CONST_INLINE) { - Py_INCREF(val); - } - new_inst.operand = (uintptr_t)val; - break; - } - case _LOAD_CONST_INLINE: - case _LOAD_CONST_INLINE_BORROW: - { - _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); - if (sym_const == NULL) { - goto error; - } - // We need to incref it for it to safely decref in the - // executor finalizer. - if (opcode == _LOAD_CONST_INLINE) { - Py_INCREF(inst->operand); - } - STACK_GROW(1); - PEEK(1) = sym_const; - assert(is_const(PEEK(1))); - break; - } - case _LOAD_CONST_INLINE_WITH_NULL: - case _LOAD_CONST_INLINE_BORROW_WITH_NULL: - { - _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); - if (sym_const == NULL) { - goto error; - } - // We need to incref it for it to safely decref in the - // executor finalizer. - if (opcode == _LOAD_CONST_INLINE_WITH_NULL) { - Py_INCREF(inst->operand); - } - STACK_GROW(1); - PEEK(1) = sym_const; - assert(is_const(PEEK(1))); - _Py_UOpsSymType *null_sym = sym_init_push_null(ctx); - if (null_sym == NULL) { - goto error; - } - STACK_GROW(1); - PEEK(1) = null_sym; - break; - } - case STORE_FAST_MAYBE_NULL: - case STORE_FAST: { - _Py_UOpsSymType *value = PEEK(1); - GETLOCAL(oparg) = value; - STACK_SHRINK(1); - break; - } - case COPY: { - _Py_UOpsSymType *bottom = PEEK(1 + (oparg - 1)); - STACK_GROW(1); - PEEK(1) = bottom; - break; - } - - case PUSH_NULL: { - STACK_GROW(1); - _Py_UOpsSymType *null_sym = sym_init_push_null(ctx); - if (null_sym == NULL) { - goto error; - } - PEEK(1) = null_sym; - break; - } - - case _INIT_CALL_PY_EXACT_ARGS: { - // Don't put in the new frame. Leave it be so that _PUSH_FRAME - // can extract callable, self_or_null and args later. - // This also means our stack pointer diverges from the real VM. - - // IMPORTANT: make sure there is no interference - // between this and _PUSH_FRAME. That is a required invariant. - break; - } - - case _PUSH_FRAME: { - // From _INIT_CALL_PY_EXACT_ARGS - - int argcount = oparg; - // _INIT_CALL_PY_EXACT_ARGS's real stack effect in the VM. - stack_pointer += -1 - oparg; - // TOS is the new callable, above it self_or_null and args - - PyFunctionObject *func = extract_func_from_sym(PEEK(1)); - if (func == NULL) { - goto error; - } - PyCodeObject *co = (PyCodeObject *)func->func_code; - - _Py_UOpsSymType *self_or_null = PEEK(0); - assert(self_or_null != NULL); - _Py_UOpsSymType **args = &PEEK(-1); - assert(args != NULL); - if (!sym_is_type(self_or_null, NULL_TYPE) && - !sym_is_type(self_or_null, SELF_OR_NULL)) { - // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in - // VM - args--; - argcount++; - } - // This is _PUSH_FRAME's stack effect - STACK_SHRINK(1); - ctx->frame->stack_pointer = stack_pointer; - _Py_UOpsSymType **localsplus_start = ctx->n_consumed; - int n_locals_already_filled = 0; - // Can determine statically, so we interleave the new locals - // and make the current stack the new locals. - // This also sets up for true call inlining. - if (!sym_is_type(self_or_null, SELF_OR_NULL)) { - localsplus_start = args; - n_locals_already_filled = argcount; - } - if (ctx_frame_push(ctx, co, localsplus_start, n_locals_already_filled, 0) != 0){ - goto error; - } - stack_pointer = ctx->frame->stack_pointer; - break; - } - - case _POP_FRAME: { - assert(STACK_LEVEL() == 1); - _Py_UOpsSymType *retval = PEEK(1); - STACK_SHRINK(1); - ctx->frame->stack_pointer = stack_pointer; - - if (ctx_frame_pop(ctx) != 0){ - goto error; - } - stack_pointer = ctx->frame->stack_pointer; - // Push retval into new frame. - STACK_GROW(1); - PEEK(1) = retval; - break; - } - - case _CHECK_PEP_523: - /* Setting the eval frame function invalidates - * all executors, so no need to check dynamically */ - if (_PyInterpreterState_GET()->eval_frame == NULL) { - new_inst.opcode = _NOP; - } - break; - case _CHECK_GLOBALS: - case _CHECK_BUILTINS: - case _SET_IP: - case _CHECK_VALIDITY: - case _SAVE_RETURN_OFFSET: - break; default: DPRINTF(1, "Unknown opcode in abstract interpreter\n"); Py_UNREACHABLE(); diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index bf6bf66c243534..16059967861937 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1252,7 +1252,7 @@ init_interp_main(PyThreadState *tstate) if (_Py_get_xoption(&config->xoptions, L"uops") != NULL) { enabled = 1; } - enabled = 1; // TEMPORARY: always enable + // enabled = 1; // TEMPORARY: always enable if (enabled) { #else // Always enable tier two for JIT builds (ignoring the environment diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c new file mode 100644 index 00000000000000..d01c6766b8c599 --- /dev/null +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -0,0 +1,251 @@ +#include "Python.h" +#include "pycore_uops.h" +#include "pycore_uop_ids.h" + +#define op(name, ...) /* NAME is ignored */ + +typedef struct _Py_UOpsSymType _Py_UOpsSymType; +typedef struct _Py_UOpsAbstractInterpContext _Py_UOpsAbstractInterpContext; +typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame; + +extern _Py_UOpsSymType *get_local(_Py_UOpsAbstractFrame *frame, int index); +extern void set_local(_Py_UOpsAbstractFrame *frame, int index, _Py_UOpsSymType *value); + +extern _Py_UOpsSymType *new_constant(PyObject *k, _Py_UOpsAbstractInterpContext *ctx); +extern _Py_UOpsSymType *new_null(_Py_UOpsAbstractInterpContext *ctx); +extern PyObject *get_constant(_Py_UOpsSymType *o); +extern PyTypeObject *get_type(_Py_UOpsSymType *o); + +extern int is_constant(_Py_UOpsSymType *o); +extern int is_int(_Py_UOpsSymType *o); +extern int is_bool(_Py_UOpsSymType *o); +extern int is_float(_Py_UOpsSymType *o); + +extern int is_not_none(_Py_UOpsSymType *o); +extern int is_none(_Py_UOpsSymType *o); + +extern _Py_UOpsSymType *new_unknown(_Py_UOpsAbstractInterpContext *ctx); + +extern void promote_to_const(_Py_UOpsSymType *o, PyObject *k); +extern void promote_to_type(_Py_UOpsSymType *o, PyTypeObject *t); + +extern SpecializerSpace *initialize_space(void *memory, int size); + + +static int +dummy_func(void) { + + PyCodeObject *code; + int oparg; + _Py_UOpsSymType *flag; + _Py_UOpsSymType *left; + _Py_UOpsSymType *right; + _Py_UOpsSymType *value; + _Py_UOpsSymType *res; + _Py_UOpsSymType *iter; + _Py_UOpsSymType *top; + _Py_UOpsSymType *bottom; + _Py_UOpsAbstractFrame *frame; + SpecializerSpace *space; + _PyUOpInstruction *this_instr; + _PyBloomFilter *dependencies; + int modified; + +// BEGIN BYTECODES // + + op(_LOAD_FAST_CHECK, (-- value)) { + value = GETLOCAL(oparg); + // We guarantee this will error - just bail and don't optimize it. + if (sym_is_type(value, NULL_TYPE)) { + goto error; + } + } + + op(_LOAD_FAST, (-- value)) { + value = GETLOCAL(oparg); + } + + op(_LOAD_FAST_AND_CLEAR, (-- value)) { + value = GETLOCAL(oparg); + _Py_UOpsSymType *temp = sym_init_null(ctx); + if (temp == NULL) { + goto error; + } + GETLOCAL(oparg) = temp; + } + + op(_STORE_FAST, (value --)) { + GETLOCAL(oparg) = value; + } + + op(_STORE_FAST_MAYBE_NULL, (value --)) { + GETLOCAL(oparg) = value; + } + + op(_PUSH_NULL, (-- res)) { + res = sym_init_null(ctx); + if (res == NULL) { + goto error; + }; + } + + op(_GUARD_BOTH_INT, (left, right -- left: &PYLONG_TYPE, right: &PYLONG_TYPE)) { + if (sym_matches_type(left, PYLONG_TYPE, 0) && + sym_matches_type(right, PYLONG_TYPE, 0)) { + REPLACE_OP(_NOP, 0, 0); + } + } + + op(_GUARD_BOTH_FLOAT, (left, right -- left: &PYFLOAT_TYPE, right: &PYFLOAT_TYPE)) { + if (sym_matches_type(left, PYFLOAT_TYPE, 0) && + sym_matches_type(right, PYFLOAT_TYPE, 0)) { + REPLACE_OP(_NOP, 0 ,0); + } + } + + + op(_BINARY_OP_ADD_INT, (left, right -- res: &PYLONG_TYPE)) { + // TODO constant propagation + (void)left; + (void)right; + res = sym_init_unknown(ctx); + if (res == NULL) { + goto error; + } + } + + op(_LOAD_CONST, (-- value)) { + value = GETITEM(ctx, oparg); + } + + op(_LOAD_CONST_INLINE, (ptr/4 -- value)) { + _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); + if (sym_const == NULL) { + goto error; + } + value = sym_const; + assert(is_const(value)); + } + + op(_LOAD_CONST_INLINE_BORROW, (ptr/4 -- value)) { + _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); + if (sym_const == NULL) { + goto error; + } + value = sym_const; + assert(is_const(value)); + } + + op(_LOAD_CONST_INLINE_WITH_NULL, (ptr/4 -- value, null)) { + _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); + if (sym_const == NULL) { + goto error; + } + value = sym_const; + assert(is_const(value)); + _Py_UOpsSymType *null_sym = sym_init_null(ctx); + if (null_sym == NULL) { + goto error; + } + null = null_sym; + } + + op(_LOAD_CONST_INLINE_BORROW_WITH_NULL, (ptr/4 -- value, null)) { + _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); + if (sym_const == NULL) { + goto error; + } + value = sym_const; + assert(is_const(value)); + _Py_UOpsSymType *null_sym = sym_init_null(ctx); + if (null_sym == NULL) { + goto error; + } + null = null_sym; + } + + + op(_COPY, (bottom, unused[oparg-1] -- bottom, unused[oparg-1], top)) { + assert(oparg > 0); + top = bottom; + } + + op(_SWAP, (bottom, unused[oparg-2], top -- + top, unused[oparg-2], bottom)) { + } + + op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null, args[oparg] -- new_frame: _Py_UOpsAbstractFrame *)) { + int argcount = oparg; + + PyFunctionObject *func = extract_func_from_sym(callable); + if (func == NULL) { + goto error; + } + PyCodeObject *co = (PyCodeObject *)func->func_code; + + assert(self_or_null != NULL); + assert(args != NULL); + if (!sym_is_type(self_or_null, NULL_TYPE) && + !sym_is_type(self_or_null, SELF_OR_NULL)) { + // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in + // VM + args--; + argcount++; + } + + _Py_UOpsSymType **localsplus_start = ctx->n_consumed; + int n_locals_already_filled = 0; + // Can determine statically, so we interleave the new locals + // and make the current stack the new locals. + // This also sets up for true call inlining. + if (!sym_is_type(self_or_null, SELF_OR_NULL)) { + localsplus_start = args; + n_locals_already_filled = argcount; + } + new_frame = ctx_frame_new(ctx, co, localsplus_start, n_locals_already_filled, 0); + if (new_frame == NULL){ + goto error; + } + } + + op(_POP_FRAME, (retval -- res)) { + SYNC_SP(); + ctx->frame->stack_pointer = stack_pointer; + ctx_frame_pop(ctx); + stack_pointer = ctx->frame->stack_pointer; + res = retval; + } + + op(_PUSH_FRAME, (new_frame: _Py_UOpsAbstractFrame * -- unused if (0))) { + SYNC_SP(); + ctx->frame->stack_pointer = stack_pointer; + ctx->frame = new_frame; + ctx->curr_frame_depth++; + stack_pointer = new_frame->stack_pointer; + } + + op(_UNPACK_EX, (seq -- values[oparg & 0xFF], unused, unused[oparg >> 8])) { + /* This has to be done manually */ + int totalargs = (oparg & 0xFF) + (oparg >> 8) + 1; + for (int i = 0; i < totalargs; i++) { + values[i] = sym_init_unknown(ctx); + if (values[i] == NULL) { + goto error; + } + } + } + + op(_CHECK_PEP_523, (--)) { + /* Setting the eval frame function invalidates + * all executors, so no need to check dynamically */ + if (_PyInterpreterState_GET()->eval_frame == NULL) { + REPLACE_OP(_NOP, 0, 0); + } + } + + + + +// END BYTECODES // + +} \ No newline at end of file diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index 7faa415232cdef..3b5deff12ff1dd 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -3,8 +3,6 @@ import parser from typing import Optional -from tier2_abstract_common import SPECIALLY_HANDLED_ABSTRACT_INSTR, SPECIAL_GUARDS - @dataclass class Properties: escapes: bool @@ -25,8 +23,6 @@ class Properties: pure: bool passthrough: bool - guard: bool - specially_handled_in_optimizer: bool def dump(self, indent: str) -> None: print(indent, end="") @@ -53,8 +49,6 @@ def from_list(properties: list["Properties"]) -> "Properties": has_free=any(p.has_free for p in properties), pure=all(p.pure for p in properties), passthrough=all(p.passthrough for p in properties), - guard=all(p.guard for p in properties), - specially_handled_in_optimizer=False, ) @@ -76,8 +70,6 @@ def from_list(properties: list["Properties"]) -> "Properties": has_free=False, pure=False, passthrough=False, - guard=False, - specially_handled_in_optimizer=False, ) @@ -477,8 +469,6 @@ def compute_properties(op: parser.InstDef) -> Properties: has_free=has_free, pure="pure" in op.annotations, passthrough=passthrough, - guard=op.name in SPECIAL_GUARDS or (passthrough and deopts and infallible), - specially_handled_in_optimizer=op.name in SPECIALLY_HANDLED_ABSTRACT_INSTR, ) diff --git a/Tools/cases_generator/generators_common.py b/Tools/cases_generator/generators_common.py index 0e804859668d27..8ec0d79b3841fc 100644 --- a/Tools/cases_generator/generators_common.py +++ b/Tools/cases_generator/generators_common.py @@ -211,10 +211,6 @@ def cflags(p: Properties) -> str: flags.append("HAS_ESCAPES_FLAG") if p.pure: flags.append("HAS_PURE_FLAG") - if p.guard: - flags.append("HAS_GUARD_FLAG") - if p.specially_handled_in_optimizer: - flags.append("HAS_SPECIAL_OPT_FLAG") if flags: return " | ".join(flags) else: diff --git a/Tools/cases_generator/tier2_abstract_common.py b/Tools/cases_generator/tier2_abstract_common.py deleted file mode 100644 index 92e896565c43d2..00000000000000 --- a/Tools/cases_generator/tier2_abstract_common.py +++ /dev/null @@ -1,34 +0,0 @@ -# We have to keep this here instead of tier2_abstract_generator.py -# to avoid a circular import. -SPECIALLY_HANDLED_ABSTRACT_INSTR = { - "LOAD_FAST", - "LOAD_FAST_CHECK", - "LOAD_FAST_AND_CLEAR", - "LOAD_CONST", - "STORE_FAST", - "STORE_FAST_MAYBE_NULL", - "COPY", - "PUSH_NULL", - # Frame stuff - "_PUSH_FRAME", - "_POP_FRAME", - "_INIT_CALL_PY_EXACT_ARGS", - # Bookkeeping - "_SET_IP", - "_CHECK_VALIDITY", - "_SAVE_RETURN_OFFSET", - "_CHECK_PEP_523", - "_CHECK_GLOBALS", - "_CHECK_BUILTINS", - # Custom tier 2 things - "_LOAD_CONST_INLINE", - "_LOAD_CONST_INLINE_WITH_NULL", - "_LOAD_CONST_INLINE_BORROW", - "_LOAD_CONST_INLINE_BORROW_WITH_NULL", -} - -SPECIAL_GUARDS = { - "_CHECK_PEP_523", - "_CHECK_GLOBALS", - "_CHECK_BUILTINS", -} diff --git a/Tools/cases_generator/tier2_abstract_generator.py b/Tools/cases_generator/tier2_abstract_generator.py index 73418c4269906b..c04924e179932e 100644 --- a/Tools/cases_generator/tier2_abstract_generator.py +++ b/Tools/cases_generator/tier2_abstract_generator.py @@ -1,12 +1,11 @@ -"""Generate the cases for the tier 2 abstract interpreter. -Reads the instruction definitions from bytecodes.c. -Writes the cases to abstract_interp_cases.c.h, which is #included in optimizer_analysis.c +"""Generate the cases for the tier 2 redundancy eliminator/abstract interpreter. +Reads the instruction definitions from bytecodes.c. and tier2_redundancy_eliminator.bytecodes.c +Writes the cases to tier2_abstract_cases.c.h, which is #included in ceval.c. """ import argparse import os.path import sys -import dataclasses from analyzer import ( Analysis, @@ -24,342 +23,130 @@ write_header, emit_tokens, emit_to, - REPLACEMENT_FUNCTIONS, + replace_sync_sp, ) -from tier2_abstract_common import SPECIALLY_HANDLED_ABSTRACT_INSTR -from tier2_generator import tier2_replace_error from cwriter import CWriter from typing import TextIO, Iterator from lexer import Token -from stack import StackOffset, Stack, SizeMismatch, UNUSED +from stack import StackOffset, Stack, SizeMismatch DEFAULT_OUTPUT = ROOT / "Python/abstract_interp_cases.c.h" +DEFAULT_ABSTRACT_INUPT = ROOT / "Python/tier2_redundancy_eliminator_bytecodes.c" +def validate_uop(override: Uop, uop: Uop) -> None: + # To do + pass -NO_CONST_OR_TYPE_EVALUATE = { - "_RESUME_CHECK", - "_GUARD_GLOBALS_VERSION", - "_GUARD_BUILTINS_VERSION", - "_CHECK_MANAGED_OBJECT_HAS_VALUES", - "_CHECK_PEP_523", - "_CHECK_STACK_SPACE", - "_INIT_CALL_PY_EXACT_ARGS", - "_END_SEND", - "_POP_TOP", - "_NOP", - "_SWAP", -} +def type_name(var: StackItem) -> str: + if var.is_array(): + return f"_Py_UOpsSymType **" + if var.type: + return var.type + return f"_Py_UOpsSymType *" -MANGLED_NULL = "__null_" - -def declare_variables( - uop: Uop, - out: CWriter, - default_type: str = "_Py_UOpsSymType *", - skip_inputs: bool = False, - skip_peeks: bool = False, -) -> None: - # Don't declare anything for these guards, they will always be evaluated. - if uop.properties.guard and uop.name in NO_CONST_OR_TYPE_EVALUATE: - return - variables = set(UNUSED) - if not skip_inputs: - for var in reversed(uop.stack.inputs): - if skip_peeks and var.peek: - continue - if var.name not in variables: - type = default_type - if var.size != "1" and var.type == "PyObject **": - type = "_Py_UOpsSymType **" - variables.add(var.name) - if var.condition: - out.emit(f"{type}{var.name} = NULL;\n") - else: - out.emit(f"{type}{var.name};\n") - if var.name == MANGLED_NULL and not var.peek: - out.emit(f"{var.name} = sym_init_push_null(ctx);\n") - out.emit(f"if ({var.name} == NULL) {{ goto error; }}\n") - for var in uop.stack.outputs: - if skip_peeks and var.peek: +def declare_variables(uop: Uop, out: CWriter, peeks: bool) -> None: + variables = {"unused"} + for var in reversed(uop.stack.inputs): + if var.peek and not peeks: continue - if var.size != "1": + if var.name not in variables: + variables.add(var.name) + if var.condition: + out.emit(f"{type_name(var)}{var.name} = sym_init_null(ctx);\n") + out.emit(f"if({var.name}) {{goto error;}}\n") + else: + out.emit(f"{type_name(var)}{var.name};\n") + for var in uop.stack.outputs: + if var.peek and not peeks: continue if var.name not in variables: variables.add(var.name) - type = default_type - if var.size != "1" and var.type == "PyObject **": - type = "_Py_UOpsSymType **" if var.condition: - out.emit(f"{type}{var.name} = NULL;\n") + out.emit(f"{type_name(var)}{var.name} = sym_init_null(ctx);\n") + out.emit(f"if({var.name}) {{goto error;}}\n") else: - out.emit(f"{type}{var.name};\n") - if var.name == MANGLED_NULL and not var.peek: - out.emit(f"{var.name} = sym_init_push_null(ctx);\n") - out.emit(f"if ({var.name} == NULL) {{ goto error; }}\n") - - -def tier2_replace_deopt( - out: CWriter, - tkn: Token, - tkn_iter: Iterator[Token], - uop: Uop, - unused: Stack, - inst: Instruction | None, -) -> None: - out.emit_at("if ", tkn) - out.emit(next(tkn_iter)) - emit_to(out, tkn_iter, "RPAREN") - next(tkn_iter) # Semi colon - out.emit(") goto error;\n") - - -TIER2_REPLACEMENT_FUNCTIONS = REPLACEMENT_FUNCTIONS.copy() -TIER2_REPLACEMENT_FUNCTIONS["ERROR_IF"] = tier2_replace_error -TIER2_REPLACEMENT_FUNCTIONS["DEOPT_IF"] = tier2_replace_deopt - -def _write_body_abstract_interp_impure_uop( - mangled_uop: Uop, uop: Uop, out: CWriter, stack: Stack + out.emit(f"{type_name(var)}{var.name};\n") + +def decref_inputs( + out: CWriter, + tkn: Token, + tkn_iter: Iterator[Token], + uop: Uop, + stack: Stack, + inst: Instruction | None, ) -> None: - # Simply make all outputs effects unknown - - for var in mangled_uop.stack.outputs: - if (var.name in UNUSED and var.size == "1") or var.peek: - continue - - if var.size == "1": - if var.name != MANGLED_NULL: + next(tkn_iter) + next(tkn_iter) + next(tkn_iter) + out.emit_at("", tkn) + +def emit_default(out: CWriter, uop: Uop) -> None: + for i, var in enumerate(uop.stack.outputs): + if var.name != "unused" and not var.peek: + if var.is_array(): + out.emit(f"for (int _i = {var.size}; --_i >= 0;) {{\n") + out.emit(f"{var.name}[_i] = sym_init_unknown(ctx);\n") + out.emit(f"if ({var.name}[_i] == NULL) goto error;\n") + out.emit("}\n") + elif var.name == "null": out.emit(f"{var.name} = sym_init_unknown(ctx);\n") - out.emit(f"if({var.name} == NULL) goto error;\n") - if var.type_prop: - out.emit(f"sym_set_type({var.name}, {var.type_prop[0]}, 0);\n") - else: - # See UNPACK_SEQUENCE for when we need this. - out.emit( - f"for (int case_gen_i = 0; case_gen_i < ({var.size}); case_gen_i++) {{\n" - ) - out.emit(f"*(stack_pointer + case_gen_i) = sym_init_unknown(ctx);\n") - out.emit(f"if(*(stack_pointer + case_gen_i) == NULL) goto error;\n") - if var.type_prop: - out.emit( - f"sym_set_type(*(stack_pointer + case_gen_i), {var.type_prop[0]}, 0);\n" - ) - out.emit("}\n") - - -def mangle_uop_names(uop: Uop) -> Uop: - uop = dataclasses.replace(uop) - new_stack = dataclasses.replace(uop.stack) - new_stack.inputs = [ - dataclasses.replace(var, name=f"__{var.name}_") for var in uop.stack.inputs - ] - new_stack.outputs = [ - dataclasses.replace(var, name=f"__{var.name}_") for var in uop.stack.outputs - ] - uop.stack = new_stack - return uop - - -# Returns a tuple of a pointer to an array of subexpressions, the length of said array -# and a string containing the join of all other subexpressions obtained from stack input. -# This grabs variadic inputs that depend on things like oparg or cache -def get_subexpressions( - input_vars: list[StackItem], -) -> tuple[str | None, int | str, str]: - arr_var = [(var.name, var) for var in input_vars if var.size > "1"] - assert len(arr_var) <= 1, "Can have at most one array input from oparg/cache" - arr_var_name = arr_var[0][0] if len(arr_var) == 1 else None - arr_var_size = (arr_var[0][1].size or 0) if arr_var_name is not None else 0 - if arr_var_name is not None: - input_vars.remove(arr_var[0][1]) - var = ", ".join([v.name for v in input_vars]) - if var: - var = ", " + var - return arr_var_name, arr_var_size, var - - -def new_sym( - constant: str | None, -) -> str: - return ( - f"_Py_UOpsSymType_New(" - f"ctx, {constant or 'NULL'});" - ) - - -def declare_caches(uop: Uop, out: CWriter) -> None: - for cache in uop.caches: - if cache.name not in UNUSED: - if cache.size == 4: - type = cast = "PyObject *" + out.emit(f"if ({var.name} == NULL) goto error;\n") else: - type = f"uint{cache.size*16}_t " - cast = f"uint{cache.size*16}_t" - out.emit(f"{type}{cache.name} = ({cast})CURRENT_OPERAND();\n") - - -def _write_body_abstract_interp_pure_uop( - mangled_uop: Uop, uop: Uop, out: CWriter, stack: Stack -) -> None: - arr_var_name, arr_var_size, subexpressions = get_subexpressions( - mangled_uop.stack.inputs - ) - - # uop is non-trivial - we cannot const evaluate it - if uop.name in NO_CONST_OR_TYPE_EVALUATE: - for in_ in mangled_uop.stack.inputs: - out.emit(f"(void){in_.name};\n") - return - - # Constant prop handled no variadic inputs. - # Perhaps in the future we can support these. - if all(input.size == "1" for input in uop.stack.inputs): - # We can try a constant evaluation - out.emit("// Constant evaluation\n") - predicates = " && ".join( - [ - f"is_const({var.name})" - for var in mangled_uop.stack.inputs - if var.name not in UNUSED - ] - ) - - if predicates: - declare_caches(uop, out) - - out.emit(f"if ({predicates or 0}) {{\n") - declare_variables(uop, out, default_type="PyObject *") - for var, mangled_var in zip(uop.stack.inputs, mangled_uop.stack.inputs): - out.emit(f"{var.name} = get_const({mangled_var.name});\n") - emit_tokens(out, uop, stack, None, TIER2_REPLACEMENT_FUNCTIONS) - out.emit("\n") - const_val = f"(PyObject *){uop.stack.outputs[0].name}" - maybe_const_val = new_sym(const_val) - out.emit(f"{mangled_uop.stack.outputs[0].name} = {maybe_const_val}\n") - out.emit(f"if({mangled_uop.stack.outputs[0].name} == NULL) {{ goto error; }}\n") - out.emit(f"if (emit_const(&ctx->emitter, {const_val}, " - f"{len(uop.stack.inputs)}) < 0) {{ goto error; }}\n") - out.emit("new_inst.opcode = _NOP;\n") - out.emit("}\n") - if not mangled_uop.stack.outputs[0].peek: - out.emit("else {\n") - sym = new_sym(None) - out.emit(f"{mangled_uop.stack.outputs[0].name} = {sym}\n") - out.emit(f"if ({mangled_uop.stack.outputs[0].name} == NULL) {{ goto error; }}\n") - out.emit("}\n") - - out.emit(f"if ({mangled_uop.stack.outputs[0].name} == NULL) goto error;\n") - - # Perform type propagation - if (typ := uop.stack.outputs[0].type_prop) is not None: - typname, aux = typ - aux = "0" if aux is None else aux - out.emit("// Type propagation\n") - out.emit( - f"sym_set_type({mangled_uop.stack.outputs[0].name}, {typname}, (uint32_t){aux});" - ) - + out.emit(f"{var.name} = sym_init_unknown(ctx);\n") + out.emit(f"if ({var.name} == NULL) goto error;\n") -def _write_body_abstract_interp_guard_uop( - mangled_uop: Uop, uop: Uop, out: CWriter, stack: Stack +def write_uop( + override: Uop | None, uop: Uop, out: CWriter, stack: Stack, debug: bool ) -> None: - # 1. Attempt to perform guard elimination - # 2. Type propagate for guard success - if uop.name in NO_CONST_OR_TYPE_EVALUATE: - return - - out.emit("// Constant evaluation\n") - predicates_str = " && ".join( - [ - f"is_const({var.name})" - for var in mangled_uop.stack.inputs - if var.name not in UNUSED - ] - ) - if predicates_str: - declare_caches(uop, out) - out.emit(f"if ({predicates_str}) {{\n") - declare_variables(uop, out, default_type="PyObject *") - for var, mangled_var in zip(uop.stack.inputs, mangled_uop.stack.inputs): - if var.name in UNUSED: - continue - out.emit(f"{var.name} = get_const({mangled_var.name});\n") - emit_tokens(out, uop, stack, None, TIER2_REPLACEMENT_FUNCTIONS) - out.emit("\n") - # Guard elimination - out.emit('DPRINTF(3, "const eliminated guard\\n");\n') - out.emit("new_inst.opcode = _NOP;\n") - out.emit("break;\n") - out.emit("}\n") - - # Does the input specify typed inputs? - if not any(output_var.type_prop for output_var in mangled_uop.stack.outputs): - return - # If the input types already match, eliminate the guard - # Read the cache information to check the auxiliary type information - predicates = [] - propagates = [] - - assert len(mangled_uop.stack.outputs) == len( - mangled_uop.stack.inputs - ), "guards must have same number of args" - assert [ - output == input_ - for output, input_ in zip(mangled_uop.stack.outputs, mangled_uop.stack.inputs) - ], "guards must forward their stack values" - for output_var in mangled_uop.stack.outputs: - if output_var.name in UNUSED: - continue - if (typ := output_var.type_prop) is not None: - typname, aux = typ - aux = "0" if aux is None else aux - # Check that the input type information match (including auxiliary info) - predicates.append( - f"sym_matches_type((_Py_UOpsSymType *){output_var.name}, {typname}, (uint32_t){aux})" - ) - # Propagate mode - set the types - propagates.append( - f"sym_set_type((_Py_UOpsSymType *){output_var.name}, {typname}, (uint32_t){aux})" - ) - - out.emit("// Type guard elimination\n") - out.emit(f"if ({' && '.join(predicates)}) {{\n") - out.emit('DPRINTF(2, "type propagation eliminated guard\\n");\n') - out.emit("new_inst.opcode = _NOP;\n") - out.emit("break;\n") - out.emit("}\n") - # Else we need the guard - out.emit("else {\n") - out.emit("// Type propagation\n") - for prop in propagates: - out.emit(f"{prop};\n") - out.emit("}\n") - - -def write_abstract_uop(mangled_uop: Uop, uop: Uop, out: CWriter, stack: Stack) -> None: try: + prototype = override if override else uop + has_type_prop = any(output.type_prop is not None for output in uop.stack.outputs) + peeks = override is not None or has_type_prop out.start_line() - is_impure = not mangled_uop.properties.pure and not mangled_uop.properties.guard - # These types of guards do not need the stack at all. - if not ( - mangled_uop.properties.guard - and mangled_uop.name in NO_CONST_OR_TYPE_EVALUATE - ): - for var in reversed(mangled_uop.stack.inputs): - definition = stack.pop(var) - if not is_impure: - out.emit(definition) - if not mangled_uop.properties.stores_sp: - for i, var in enumerate(mangled_uop.stack.outputs): - definition = stack.push(var) - if not (is_impure and var.size != "1"): - out.emit(definition) - if uop.properties.pure: - _write_body_abstract_interp_pure_uop(mangled_uop, uop, out, stack) - elif uop.properties.guard: - _write_body_abstract_interp_guard_uop(mangled_uop, uop, out, stack) + for var in reversed(prototype.stack.inputs): + if not var.peek or peeks: + out.emit(stack.pop(var)) + if not prototype.properties.stores_sp: + for i, var in enumerate(prototype.stack.outputs): + if not var.peek or peeks: + out.emit(stack.push(var)) + if debug: + args = [] + for var in prototype.stack.inputs: + if not var.peek or peeks: + args.append(var.name) + out.emit(f'DEBUG_PRINTF({", ".join(args)});\n') + if override or has_type_prop: + for cache in uop.caches: + if cache.name != "unused": + if cache.size == 4: + type = cast = "PyObject *" + else: + type = f"uint{cache.size*16}_t " + cast = f"uint{cache.size*16}_t" + out.emit(f"{type}{cache.name} = ({cast})inst->operand;\n") + if override: + replacement_funcs = { + "DECREF_INPUTS": decref_inputs, + "SYNC_SP": replace_sync_sp + } + emit_tokens(out, override, stack, None, replacement_funcs) else: - _write_body_abstract_interp_impure_uop(mangled_uop, uop, out, stack) + emit_default(out, uop) + # Type propagation + for output in uop.stack.outputs: + if (typ := output.type_prop): + typname, refinement = typ + refinement = refinement or "0" + out.emit(f"sym_set_type({output.name}, {typname}, {refinement});\n") + + if prototype.properties.stores_sp: + for i, var in enumerate(prototype.stack.outputs): + if not var.peek or peeks: + out.emit(stack.push(var)) + out.start_line() + stack.flush(out) except SizeMismatch as ex: raise analysis_error(ex.args[0], uop.body[0]) @@ -367,23 +154,17 @@ def write_abstract_uop(mangled_uop: Uop, uop: Uop, out: CWriter, stack: Stack) - SKIPS = ("_EXTENDED_ARG",) -def generate_tier2_abstract( - filenames: list[str], analysis: Analysis, outfile: TextIO, lines: bool +def generate_abstract_interpreter( + filenames: list[str], abstract: Analysis, base: Analysis, outfile: TextIO, debug: bool ) -> None: write_header(__file__, filenames, outfile) - outfile.write( - """ -#ifdef TIER_ONE - #error "This file is for Tier 2 only" -#endif -#define TIER_TWO 2 -""" - ) - out = CWriter(outfile, 2, lines) + out = CWriter(outfile, 2, False) out.emit("\n") - for name, uop in analysis.uops.items(): - if name in SPECIALLY_HANDLED_ABSTRACT_INSTR: - continue + for uop in base.uops.values(): + override: Uop | None = None + if uop.name in abstract.uops: + override = abstract.uops[uop.name] + validate_uop(override, uop) if uop.properties.tier_one_only: continue if uop.is_super(): @@ -392,21 +173,17 @@ def generate_tier2_abstract( out.emit(f"/* {uop.name} is not a viable micro-op for tier 2 */\n\n") continue out.emit(f"case {uop.name}: {{\n") - mangled_uop = mangle_uop_names(uop) - is_impure = not (mangled_uop.properties.pure or mangled_uop.properties.guard) - declare_variables(mangled_uop, out, skip_inputs=is_impure, skip_peeks=is_impure) + if override: + declare_variables(override, out, True) + else: + has_type_prop = any(output.type_prop is not None for output in uop.stack.outputs) + declare_variables(uop, out, has_type_prop) stack = Stack() - write_abstract_uop(mangled_uop, uop, out, stack) - out.start_line() - if not uop.properties.always_exits: - # Guards strictly only peek - if not uop.properties.guard: - stack.flush(out, cast_type="_Py_UOpsSymType *") - out.emit("break;\n") + write_uop(override, uop, out, stack, debug) out.start_line() + out.emit("break;\n") out.emit("}") out.emit("\n\n") - outfile.write("#undef TIER_TWO\n") arg_parser = argparse.ArgumentParser( @@ -418,18 +195,25 @@ def generate_tier2_abstract( "-o", "--output", type=str, help="Generated code", default=DEFAULT_OUTPUT ) + +arg_parser.add_argument( + "input", nargs=1, help="Abstract interpreter definition file" +) + arg_parser.add_argument( - "-l", "--emit-line-directives", help="Emit #line directives", action="store_true" + "base", nargs=argparse.REMAINDER, help="The base instruction definition file(s)" ) arg_parser.add_argument( - "input", nargs=argparse.REMAINDER, help="Instruction definition file(s)" + "-d", "--debug", help="Insert debug calls", action="store_true" ) if __name__ == "__main__": args = arg_parser.parse_args() - if len(args.input) == 0: + if len(args.base) == 0: args.input.append(DEFAULT_INPUT) - data = analyze_files(args.input) + args.input.append(DEFAULT_ABSTRACT_INUPT) + abstract = analyze_files(args.input) + base = analyze_files(args.base) with open(args.output, "w") as outfile: - generate_tier2_abstract(args.input, data, outfile, args.emit_line_directives) + generate_abstract_interpreter(args.input, abstract, base, outfile, args.debug) \ No newline at end of file diff --git a/Tools/cases_generator/uop_metadata_generator.py b/Tools/cases_generator/uop_metadata_generator.py index e5d74b436991c0..1d5df000e52839 100644 --- a/Tools/cases_generator/uop_metadata_generator.py +++ b/Tools/cases_generator/uop_metadata_generator.py @@ -15,7 +15,6 @@ write_header, cflags, ) -from stack import Stack from cwriter import CWriter from typing import TextIO @@ -40,26 +39,6 @@ def generate_names_and_flags(analysis: Analysis, out: CWriter) -> None: out.emit("};\n") out.emit("#endif // NEED_OPCODE_METADATA\n\n") - -def generate_net_stack_effect(analysis: Analysis, out: CWriter) -> None: - out.emit("extern int _PyUop_NetStackEffect(int opcode, int oparg);\n") - out.emit("#ifdef NEED_OPCODE_METADATA\n") - out.emit("int _PyUop_NetStackEffect(int opcode, int oparg) {\n") - out.emit("switch (opcode) {\n") - for uop in analysis.uops.values(): - if uop.is_viable() and not uop.properties.tier_one_only: - out.emit(f"case {uop.name}:\n") - stack = Stack() - for inputs in uop.stack.inputs: - stack.pop(inputs) - for outputs in uop.stack.outputs: - stack.push(outputs) - out.emit(f"return ({stack.top_offset.to_c()});\n") - out.emit("default: Py_UNREACHABLE();\n") - out.emit("};\n") - out.emit("};\n\n") - out.emit("#endif // NEED_OPCODE_METADATA\n\n") - def generate_uop_metadata( filenames: list[str], analysis: Analysis, outfile: TextIO ) -> None: @@ -69,7 +48,6 @@ def generate_uop_metadata( out.emit("#include \n") out.emit('#include "pycore_uop_ids.h"\n') generate_names_and_flags(analysis, out) - generate_net_stack_effect(analysis, out) arg_parser = argparse.ArgumentParser( From e8a8b78962999874510863ae92bf80686f9563c5 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 6 Feb 2024 15:35:48 +0800 Subject: [PATCH 03/52] reduce diff Co-Authored-By: Jules <57632293+JuliaPoo@users.noreply.github.com> Co-Authored-By: Guido van Rossum --- Include/internal/pycore_opcode_metadata.h | 36 ++++++++-------- Include/internal/pycore_uop_metadata.h | 42 +++++++++---------- Python/optimizer.c | 18 -------- Python/optimizer_analysis.c | 3 +- Python/pylifecycle.c | 2 +- .../tier2_redundancy_eliminator_bytecodes.c | 28 +------------ Tools/cases_generator/generators_common.py | 2 + .../opcode_metadata_generator.py | 3 +- .../cases_generator/uop_metadata_generator.py | 1 + 9 files changed, 46 insertions(+), 89 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 87c1150befa903..389468010e83d2 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -910,8 +910,7 @@ enum InstructionFormat { #define HAS_ERROR_FLAG (256) #define HAS_ESCAPES_FLAG (512) #define HAS_PURE_FLAG (1024) -#define HAS_GUARD_FLAG (2048) -#define HAS_SPECIAL_OPT_FLAG (4096) +#define HAS_PASSTHROUGH_FLAG (2048) #define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ARG_FLAG)) #define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_CONST_FLAG)) #define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NAME_FLAG)) @@ -923,8 +922,7 @@ enum InstructionFormat { #define OPCODE_HAS_ERROR(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ERROR_FLAG)) #define OPCODE_HAS_ESCAPES(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ESCAPES_FLAG)) #define OPCODE_HAS_PURE(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_PURE_FLAG)) -#define OPCODE_HAS_GUARD(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_GUARD_FLAG)) -#define OPCODE_HAS_SPECIAL_OPT(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_SPECIAL_OPT_FLAG)) +#define OPCODE_HAS_PASSTHROUGH(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_PASSTHROUGH_FLAG)) #define OPARG_FULL 0 #define OPARG_CACHE_1 1 @@ -1002,7 +1000,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [COMPARE_OP_STR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, [CONTAINS_OP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CONVERT_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, - [COPY] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG }, + [COPY] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, [COPY_FREE_VARS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [DELETE_ATTR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [DELETE_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1013,8 +1011,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [DICT_MERGE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [DICT_UPDATE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [END_ASYNC_FOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [END_FOR] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, - [END_SEND] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, + [END_FOR] = { true, INSTR_FMT_IX, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, + [END_SEND] = { true, INSTR_FMT_IX, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG }, [EXIT_INIT_CHECK] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [EXTENDED_ARG] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, @@ -1073,9 +1071,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, [LOAD_BUILD_CLASS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_PURE_FLAG }, + [LOAD_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, [LOAD_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG }, + [LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, [LOAD_FAST_AND_CLEAR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ERROR_FLAG }, [LOAD_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, @@ -1096,15 +1094,15 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [MATCH_KEYS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [MATCH_MAPPING] = { true, INSTR_FMT_IX, 0 }, [MATCH_SEQUENCE] = { true, INSTR_FMT_IX, 0 }, - [NOP] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, + [NOP] = { true, INSTR_FMT_IX, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, [POP_EXCEPT] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, - [POP_TOP] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, + [POP_TOP] = { true, INSTR_FMT_IX, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, [PUSH_EXC_INFO] = { true, INSTR_FMT_IX, 0 }, - [PUSH_NULL] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, + [PUSH_NULL] = { true, INSTR_FMT_IX, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, [RAISE_VARARGS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [RERAISE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [RESERVED] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, @@ -1133,7 +1131,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [STORE_SUBSCR] = { true, INSTR_FMT_IXC, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [STORE_SUBSCR_DICT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [STORE_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, - [SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG }, + [SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, [TO_BOOL] = { true, INSTR_FMT_IXC00, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [TO_BOOL_ALWAYS_TRUE] = { true, INSTR_FMT_IXC00, HAS_DEOPT_FLAG }, [TO_BOOL_BOOL] = { true, INSTR_FMT_IXC00, HAS_DEOPT_FLAG }, @@ -1143,7 +1141,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [TO_BOOL_STR] = { true, INSTR_FMT_IXC00, HAS_DEOPT_FLAG }, [UNARY_INVERT] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [UNARY_NEGATIVE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [UNARY_NOT] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, + [UNARY_NOT] = { true, INSTR_FMT_IX, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, [UNPACK_EX] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [UNPACK_SEQUENCE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [UNPACK_SEQUENCE_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, @@ -1153,15 +1151,15 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ESCAPES_FLAG }, [JUMP] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [JUMP_NO_INTERRUPT] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG }, - [LOAD_CLOSURE] = { true, -1, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG }, + [LOAD_CLOSURE] = { true, -1, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, [LOAD_METHOD] = { true, -1, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_SUPER_METHOD] = { true, -1, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_ZERO_SUPER_ATTR] = { true, -1, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_ZERO_SUPER_METHOD] = { true, -1, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [POP_BLOCK] = { true, -1, HAS_PURE_FLAG }, - [SETUP_CLEANUP] = { true, -1, HAS_PURE_FLAG | HAS_ARG_FLAG }, - [SETUP_FINALLY] = { true, -1, HAS_PURE_FLAG | HAS_ARG_FLAG }, - [SETUP_WITH] = { true, -1, HAS_PURE_FLAG | HAS_ARG_FLAG }, + [POP_BLOCK] = { true, -1, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, + [SETUP_CLEANUP] = { true, -1, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG | HAS_ARG_FLAG }, + [SETUP_FINALLY] = { true, -1, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG | HAS_ARG_FLAG }, + [SETUP_WITH] = { true, -1, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG | HAS_ARG_FLAG }, [STORE_FAST_MAYBE_NULL] = { true, -1, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, }; #endif diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index f333e0041c13ec..432eaf268bec86 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -16,21 +16,21 @@ 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] = HAS_PURE_FLAG, + [_NOP] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, [_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 | HAS_PURE_FLAG, + [_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, [_LOAD_FAST_AND_CLEAR] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, [_LOAD_FAST_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, - [_LOAD_CONST] = HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_PURE_FLAG, + [_LOAD_CONST] = HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_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] = HAS_PURE_FLAG, - [_PUSH_NULL] = HAS_PURE_FLAG, - [_END_SEND] = HAS_PURE_FLAG, + [_POP_TOP] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_PUSH_NULL] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_END_SEND] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, [_UNARY_NEGATIVE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_UNARY_NOT] = HAS_PURE_FLAG, + [_UNARY_NOT] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, [_TO_BOOL] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_TO_BOOL_BOOL] = HAS_DEOPT_FLAG, [_TO_BOOL_INT] = HAS_DEOPT_FLAG, @@ -40,15 +40,15 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_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 | HAS_PURE_FLAG, - [_BINARY_OP_ADD_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, - [_BINARY_OP_SUBTRACT_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, + [_BINARY_OP_MULTIPLY_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_BINARY_OP_ADD_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_BINARY_OP_SUBTRACT_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, [_GUARD_BOTH_FLOAT] = HAS_DEOPT_FLAG, - [_BINARY_OP_MULTIPLY_FLOAT] = HAS_PURE_FLAG, - [_BINARY_OP_ADD_FLOAT] = HAS_PURE_FLAG, - [_BINARY_OP_SUBTRACT_FLOAT] = HAS_PURE_FLAG, + [_BINARY_OP_MULTIPLY_FLOAT] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_BINARY_OP_ADD_FLOAT] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_BINARY_OP_SUBTRACT_FLOAT] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, [_GUARD_BOTH_UNICODE] = HAS_DEOPT_FLAG, - [_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_PURE_FLAG, + [_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_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, @@ -168,7 +168,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_CHECK_PEP_523] = HAS_DEOPT_FLAG, [_CHECK_FUNCTION_EXACT_ARGS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, [_CHECK_STACK_SPACE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_INIT_CALL_PY_EXACT_ARGS] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG | HAS_PURE_FLAG, + [_INIT_CALL_PY_EXACT_ARGS] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, [_PUSH_FRAME] = HAS_ESCAPES_FLAG, [_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, @@ -190,9 +190,9 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_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 | HAS_PURE_FLAG, + [_COPY] = HAS_ARG_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, [_BINARY_OP] = HAS_ARG_FLAG | HAS_ERROR_FLAG, - [_SWAP] = HAS_ARG_FLAG | HAS_PURE_FLAG, + [_SWAP] = HAS_ARG_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, [_GUARD_IS_TRUE_POP] = HAS_DEOPT_FLAG, [_GUARD_IS_FALSE_POP] = HAS_DEOPT_FLAG, [_GUARD_IS_NONE_POP] = HAS_DEOPT_FLAG, @@ -204,10 +204,10 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_JUMP_ABSOLUTE] = HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG, [_JUMP_ABSOLUTE_HEADER] = 0, [_CHECK_VALIDITY] = HAS_DEOPT_FLAG, - [_LOAD_CONST_INLINE] = HAS_PURE_FLAG, - [_LOAD_CONST_INLINE_BORROW] = HAS_PURE_FLAG, - [_LOAD_CONST_INLINE_WITH_NULL] = HAS_PURE_FLAG, - [_LOAD_CONST_INLINE_BORROW_WITH_NULL] = HAS_PURE_FLAG, + [_LOAD_CONST_INLINE] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_LOAD_CONST_INLINE_BORROW] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_LOAD_CONST_INLINE_WITH_NULL] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_LOAD_CONST_INLINE_BORROW_WITH_NULL] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, [_CHECK_GLOBALS] = HAS_DEOPT_FLAG, [_CHECK_BUILTINS] = HAS_DEOPT_FLAG, [_INTERNAL_INCREMENT_OPT_COUNTER] = 0, diff --git a/Python/optimizer.c b/Python/optimizer.c index d94f29c11da829..fb4ab99d66a21e 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -222,26 +222,8 @@ static PyMethodDef executor_methods[] = { ///////////////////// Experimental UOp Optimizer ///////////////////// -static void -clear_strong_refs_in_uops(_PyUOpInstruction *trace, Py_ssize_t uop_len) -{ - for (Py_ssize_t i = 0; i < uop_len; i++) { - if (trace[i].opcode == _LOAD_CONST_INLINE || - trace[i].opcode == _LOAD_CONST_INLINE_WITH_NULL) { - PyObject *c = (PyObject*)trace[i].operand; - Py_CLEAR(c); - } - if (trace[i].opcode == _JUMP_ABSOLUTE || - trace[i].opcode == _JUMP_TO_TOP || - trace[i].opcode == _EXIT_TRACE) { - return; - } - } -} - static void uop_dealloc(_PyExecutorObject *self) { - clear_strong_refs_in_uops(&self->trace[0], Py_SIZE(self)); _Py_ExecutorClear(self); #ifdef _Py_JIT _PyJIT_Free(self); diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 42ab4abb61813d..6384e09e8cab74 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -884,9 +884,8 @@ uop_abstract_interpret( while (curr < end && !op_is_end(curr->opcode)) { if (!(_PyUop_Flags[curr->opcode] & HAS_PURE_FLAG) && - !(_PyUop_Flags[curr->opcode] & HAS_SPECIAL_OPT_FLAG) && !op_is_bookkeeping(curr->opcode) && - !(_PyUop_Flags[curr->opcode] & HAS_GUARD_FLAG)) { + !(_PyUop_Flags[curr->opcode] & HAS_PASSTHROUGH_FLAG)) { DPRINTF(3, "Impure %s\n", _PyOpcode_uop_name[curr->opcode]); if (needs_clear_locals) { if (clear_locals_type_info(&ctx) < 0) { diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 16059967861937..bf6bf66c243534 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1252,7 +1252,7 @@ init_interp_main(PyThreadState *tstate) if (_Py_get_xoption(&config->xoptions, L"uops") != NULL) { enabled = 1; } - // enabled = 1; // TEMPORARY: always enable + enabled = 1; // TEMPORARY: always enable if (enabled) { #else // Always enable tier two for JIT builds (ignoring the environment diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index d01c6766b8c599..69f6ff5c409659 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -8,30 +8,6 @@ typedef struct _Py_UOpsSymType _Py_UOpsSymType; typedef struct _Py_UOpsAbstractInterpContext _Py_UOpsAbstractInterpContext; typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame; -extern _Py_UOpsSymType *get_local(_Py_UOpsAbstractFrame *frame, int index); -extern void set_local(_Py_UOpsAbstractFrame *frame, int index, _Py_UOpsSymType *value); - -extern _Py_UOpsSymType *new_constant(PyObject *k, _Py_UOpsAbstractInterpContext *ctx); -extern _Py_UOpsSymType *new_null(_Py_UOpsAbstractInterpContext *ctx); -extern PyObject *get_constant(_Py_UOpsSymType *o); -extern PyTypeObject *get_type(_Py_UOpsSymType *o); - -extern int is_constant(_Py_UOpsSymType *o); -extern int is_int(_Py_UOpsSymType *o); -extern int is_bool(_Py_UOpsSymType *o); -extern int is_float(_Py_UOpsSymType *o); - -extern int is_not_none(_Py_UOpsSymType *o); -extern int is_none(_Py_UOpsSymType *o); - -extern _Py_UOpsSymType *new_unknown(_Py_UOpsAbstractInterpContext *ctx); - -extern void promote_to_const(_Py_UOpsSymType *o, PyObject *k); -extern void promote_to_type(_Py_UOpsSymType *o, PyTypeObject *t); - -extern SpecializerSpace *initialize_space(void *memory, int size); - - static int dummy_func(void) { @@ -46,8 +22,8 @@ dummy_func(void) { _Py_UOpsSymType *top; _Py_UOpsSymType *bottom; _Py_UOpsAbstractFrame *frame; - SpecializerSpace *space; - _PyUOpInstruction *this_instr; + _Py_UOpsAbstractInterpContext *ctx; + _PyUOpInstruction *inst; _PyBloomFilter *dependencies; int modified; diff --git a/Tools/cases_generator/generators_common.py b/Tools/cases_generator/generators_common.py index 8ec0d79b3841fc..c93034f0635258 100644 --- a/Tools/cases_generator/generators_common.py +++ b/Tools/cases_generator/generators_common.py @@ -211,6 +211,8 @@ def cflags(p: Properties) -> str: flags.append("HAS_ESCAPES_FLAG") if p.pure: flags.append("HAS_PURE_FLAG") + if p.pure: + flags.append("HAS_PASSTHROUGH_FLAG") if flags: return " | ".join(flags) else: diff --git a/Tools/cases_generator/opcode_metadata_generator.py b/Tools/cases_generator/opcode_metadata_generator.py index b2f797fb553d85..3e9fa3e26daa53 100644 --- a/Tools/cases_generator/opcode_metadata_generator.py +++ b/Tools/cases_generator/opcode_metadata_generator.py @@ -51,8 +51,7 @@ "ERROR", "ESCAPES", "PURE", - "GUARD", - "SPECIAL_OPT", + "PASSTHROUGH", ] diff --git a/Tools/cases_generator/uop_metadata_generator.py b/Tools/cases_generator/uop_metadata_generator.py index 1d5df000e52839..9083ecc48bdf5b 100644 --- a/Tools/cases_generator/uop_metadata_generator.py +++ b/Tools/cases_generator/uop_metadata_generator.py @@ -39,6 +39,7 @@ def generate_names_and_flags(analysis: Analysis, out: CWriter) -> None: out.emit("};\n") out.emit("#endif // NEED_OPCODE_METADATA\n\n") + def generate_uop_metadata( filenames: list[str], analysis: Analysis, outfile: TextIO ) -> None: From bb6137ac95bb7eb6f21a3b4a09138ca8ce01b71d Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 6 Feb 2024 15:37:28 +0800 Subject: [PATCH 04/52] fix passthrough --- Include/internal/pycore_opcode_metadata.h | 30 ++++---- Include/internal/pycore_uop_metadata.h | 86 +++++++++++----------- Tools/cases_generator/generators_common.py | 2 +- 3 files changed, 59 insertions(+), 59 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 389468010e83d2..6b60a6fbffdc5e 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1000,7 +1000,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [COMPARE_OP_STR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, [CONTAINS_OP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CONVERT_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, - [COPY] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, + [COPY] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG }, [COPY_FREE_VARS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [DELETE_ATTR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [DELETE_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1011,8 +1011,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [DICT_MERGE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [DICT_UPDATE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [END_ASYNC_FOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [END_FOR] = { true, INSTR_FMT_IX, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, - [END_SEND] = { true, INSTR_FMT_IX, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, + [END_FOR] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, + [END_SEND] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG }, [EXIT_INIT_CHECK] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [EXTENDED_ARG] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, @@ -1071,9 +1071,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, [LOAD_BUILD_CLASS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, + [LOAD_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_PURE_FLAG }, [LOAD_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, + [LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG }, [LOAD_FAST_AND_CLEAR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ERROR_FLAG }, [LOAD_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, @@ -1094,15 +1094,15 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [MATCH_KEYS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [MATCH_MAPPING] = { true, INSTR_FMT_IX, 0 }, [MATCH_SEQUENCE] = { true, INSTR_FMT_IX, 0 }, - [NOP] = { true, INSTR_FMT_IX, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, + [NOP] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, [POP_EXCEPT] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, - [POP_TOP] = { true, INSTR_FMT_IX, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, + [POP_TOP] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, [PUSH_EXC_INFO] = { true, INSTR_FMT_IX, 0 }, - [PUSH_NULL] = { true, INSTR_FMT_IX, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, + [PUSH_NULL] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, [RAISE_VARARGS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [RERAISE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [RESERVED] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, @@ -1131,7 +1131,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [STORE_SUBSCR] = { true, INSTR_FMT_IXC, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [STORE_SUBSCR_DICT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [STORE_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, - [SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, + [SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG }, [TO_BOOL] = { true, INSTR_FMT_IXC00, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [TO_BOOL_ALWAYS_TRUE] = { true, INSTR_FMT_IXC00, HAS_DEOPT_FLAG }, [TO_BOOL_BOOL] = { true, INSTR_FMT_IXC00, HAS_DEOPT_FLAG }, @@ -1141,7 +1141,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [TO_BOOL_STR] = { true, INSTR_FMT_IXC00, HAS_DEOPT_FLAG }, [UNARY_INVERT] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [UNARY_NEGATIVE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [UNARY_NOT] = { true, INSTR_FMT_IX, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, + [UNARY_NOT] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, [UNPACK_EX] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [UNPACK_SEQUENCE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [UNPACK_SEQUENCE_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, @@ -1151,15 +1151,15 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ESCAPES_FLAG }, [JUMP] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [JUMP_NO_INTERRUPT] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG }, - [LOAD_CLOSURE] = { true, -1, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, + [LOAD_CLOSURE] = { true, -1, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG }, [LOAD_METHOD] = { true, -1, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_SUPER_METHOD] = { true, -1, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_ZERO_SUPER_ATTR] = { true, -1, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_ZERO_SUPER_METHOD] = { true, -1, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [POP_BLOCK] = { true, -1, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG }, - [SETUP_CLEANUP] = { true, -1, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG | HAS_ARG_FLAG }, - [SETUP_FINALLY] = { true, -1, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG | HAS_ARG_FLAG }, - [SETUP_WITH] = { true, -1, HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG | HAS_ARG_FLAG }, + [POP_BLOCK] = { true, -1, HAS_PURE_FLAG }, + [SETUP_CLEANUP] = { true, -1, HAS_PURE_FLAG | HAS_ARG_FLAG }, + [SETUP_FINALLY] = { true, -1, HAS_PURE_FLAG | HAS_ARG_FLAG }, + [SETUP_WITH] = { true, -1, HAS_PURE_FLAG | HAS_ARG_FLAG }, [STORE_FAST_MAYBE_NULL] = { true, -1, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, }; #endif diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 432eaf268bec86..f0a278cbfe4902 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -16,39 +16,39 @@ 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] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_NOP] = HAS_PURE_FLAG, [_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 | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_PURE_FLAG, [_LOAD_FAST_AND_CLEAR] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, [_LOAD_FAST_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG, - [_LOAD_CONST] = HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_LOAD_CONST] = HAS_ARG_FLAG | HAS_CONST_FLAG | HAS_PURE_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] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, - [_PUSH_NULL] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, - [_END_SEND] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_POP_TOP] = HAS_PURE_FLAG, + [_PUSH_NULL] = HAS_PURE_FLAG, + [_END_SEND] = HAS_PURE_FLAG, [_UNARY_NEGATIVE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_UNARY_NOT] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_UNARY_NOT] = HAS_PURE_FLAG, [_TO_BOOL] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_TO_BOOL_BOOL] = HAS_DEOPT_FLAG, + [_TO_BOOL_BOOL] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_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 | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, - [_BINARY_OP_ADD_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, - [_BINARY_OP_SUBTRACT_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, - [_GUARD_BOTH_FLOAT] = HAS_DEOPT_FLAG, - [_BINARY_OP_MULTIPLY_FLOAT] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, - [_BINARY_OP_ADD_FLOAT] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, - [_BINARY_OP_SUBTRACT_FLOAT] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, - [_GUARD_BOTH_UNICODE] = HAS_DEOPT_FLAG, - [_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_GUARD_BOTH_INT] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_BINARY_OP_MULTIPLY_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, + [_BINARY_OP_ADD_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, + [_BINARY_OP_SUBTRACT_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, + [_GUARD_BOTH_FLOAT] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_BINARY_OP_MULTIPLY_FLOAT] = HAS_PURE_FLAG, + [_BINARY_OP_ADD_FLOAT] = HAS_PURE_FLAG, + [_BINARY_OP_SUBTRACT_FLOAT] = HAS_PURE_FLAG, + [_GUARD_BOTH_UNICODE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_PURE_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, @@ -112,17 +112,17 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_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, + [_GUARD_TYPE_VERSION] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_CHECK_MANAGED_OBJECT_HAS_VALUES] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, [_LOAD_ATTR_INSTANCE_VALUE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_CHECK_ATTR_MODULE] = HAS_DEOPT_FLAG, + [_CHECK_ATTR_MODULE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, [_LOAD_ATTR_MODULE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_CHECK_ATTR_WITH_HINT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, + [_CHECK_ATTR_WITH_HINT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG | HAS_PASSTHROUGH_FLAG, [_LOAD_ATTR_WITH_HINT] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, [_LOAD_ATTR_SLOT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_CHECK_ATTR_CLASS] = HAS_DEOPT_FLAG, + [_CHECK_ATTR_CLASS] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, [_LOAD_ATTR_CLASS] = HAS_ARG_FLAG, - [_GUARD_DORV_VALUES] = HAS_DEOPT_FLAG, + [_GUARD_DORV_VALUES] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_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, @@ -142,33 +142,33 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_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_CHECK_LIST] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_GUARD_NOT_EXHAUSTED_LIST] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, [_ITER_NEXT_LIST] = 0, - [_ITER_CHECK_TUPLE] = HAS_DEOPT_FLAG, - [_GUARD_NOT_EXHAUSTED_TUPLE] = HAS_DEOPT_FLAG, + [_ITER_CHECK_TUPLE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_GUARD_NOT_EXHAUSTED_TUPLE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, [_ITER_NEXT_TUPLE] = 0, - [_ITER_CHECK_RANGE] = HAS_DEOPT_FLAG, - [_GUARD_NOT_EXHAUSTED_RANGE] = HAS_DEOPT_FLAG, + [_ITER_CHECK_RANGE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_GUARD_NOT_EXHAUSTED_RANGE] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_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, + [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_GUARD_KEYS_VERSION] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_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, + [_CHECK_ATTR_METHOD_LAZY_DICT] = HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, [_LOAD_ATTR_METHOD_LAZY_DICT] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, - [_CHECK_CALL_BOUND_METHOD_EXACT_ARGS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_CHECK_CALL_BOUND_METHOD_EXACT_ARGS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_PASSTHROUGH_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 | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_CHECK_FUNCTION_EXACT_ARGS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_CHECK_STACK_SPACE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_PASSTHROUGH_FLAG, + [_INIT_CALL_PY_EXACT_ARGS] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG | HAS_PURE_FLAG, [_PUSH_FRAME] = HAS_ESCAPES_FLAG, [_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, @@ -190,9 +190,9 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_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 | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_COPY] = HAS_ARG_FLAG | HAS_PURE_FLAG, [_BINARY_OP] = HAS_ARG_FLAG | HAS_ERROR_FLAG, - [_SWAP] = HAS_ARG_FLAG | HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_SWAP] = HAS_ARG_FLAG | HAS_PURE_FLAG, [_GUARD_IS_TRUE_POP] = HAS_DEOPT_FLAG, [_GUARD_IS_FALSE_POP] = HAS_DEOPT_FLAG, [_GUARD_IS_NONE_POP] = HAS_DEOPT_FLAG, @@ -204,10 +204,10 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_JUMP_ABSOLUTE] = HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG, [_JUMP_ABSOLUTE_HEADER] = 0, [_CHECK_VALIDITY] = HAS_DEOPT_FLAG, - [_LOAD_CONST_INLINE] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, - [_LOAD_CONST_INLINE_BORROW] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, - [_LOAD_CONST_INLINE_WITH_NULL] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, - [_LOAD_CONST_INLINE_BORROW_WITH_NULL] = HAS_PURE_FLAG | HAS_PASSTHROUGH_FLAG, + [_LOAD_CONST_INLINE] = HAS_PURE_FLAG, + [_LOAD_CONST_INLINE_BORROW] = HAS_PURE_FLAG, + [_LOAD_CONST_INLINE_WITH_NULL] = HAS_PURE_FLAG, + [_LOAD_CONST_INLINE_BORROW_WITH_NULL] = HAS_PURE_FLAG, [_CHECK_GLOBALS] = HAS_DEOPT_FLAG, [_CHECK_BUILTINS] = HAS_DEOPT_FLAG, [_INTERNAL_INCREMENT_OPT_COUNTER] = 0, diff --git a/Tools/cases_generator/generators_common.py b/Tools/cases_generator/generators_common.py index c93034f0635258..2fc2ab115321cf 100644 --- a/Tools/cases_generator/generators_common.py +++ b/Tools/cases_generator/generators_common.py @@ -211,7 +211,7 @@ def cflags(p: Properties) -> str: flags.append("HAS_ESCAPES_FLAG") if p.pure: flags.append("HAS_PURE_FLAG") - if p.pure: + if p.passthrough: flags.append("HAS_PASSTHROUGH_FLAG") if flags: return " | ".join(flags) From 9b15f9eb6ce5e122451ef7b68f3ade03fcd150c6 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 6 Feb 2024 22:38:21 +0800 Subject: [PATCH 05/52] fix tests --- Lib/test/test_capi/test_opt.py | 2 +- Python/abstract_interp_cases.c.h | 959 +++++++----------- Python/optimizer_analysis.c | 36 +- .../tier2_redundancy_eliminator_bytecodes.c | 20 +- Tools/cases_generator/stack.py | 2 +- .../tier2_abstract_generator.py | 100 +- 6 files changed, 469 insertions(+), 650 deletions(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 94a9bd30466eaa..481d5ef78c26d2 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -680,7 +680,7 @@ def testfunc(loops): self.assertIsNotNone(ex) self.assertEqual(res, 1) binop_count = [opname for opname, _, _ in ex if opname == "_BINARY_OP_ADD_INT"] - self.assertEqual(len(binop_count), 0) + self.assertEqual(len(binop_count), 2) uops = {opname for opname, _, _ in ex} self.assertNotIn("_SHRINK_STACK", uops) iter_next_count = [opname for opname, _, _ in ex if opname == "_ITER_NEXT_RANGE"] diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index 8bdba5efaba916..849cf2e1a8cd03 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -4,10 +4,12 @@ // Do not edit! case _NOP: { + break; } case _RESUME_CHECK: { + break; } @@ -63,9 +65,7 @@ } case _POP_TOP: { - _Py_UOpsSymType *value; - value = stack_pointer[-1]; - stack_pointer += -1; + break; } @@ -82,107 +82,106 @@ case _END_SEND: { _Py_UOpsSymType *value; - _Py_UOpsSymType *receiver; - value = stack_pointer[-1]; - receiver = stack_pointer[-2]; value = sym_init_unknown(ctx); if (value == NULL) goto error; - stack_pointer[-2] = value; - stack_pointer += -1; + + stack_pointer[0] = value; + stack_pointer += 1; break; } case _UNARY_NEGATIVE: { - _Py_UOpsSymType *value; _Py_UOpsSymType *res; - value = stack_pointer[-1]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-1] = res; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _UNARY_NOT: { - _Py_UOpsSymType *value; _Py_UOpsSymType *res; - value = stack_pointer[-1]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-1] = res; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _TO_BOOL: { - _Py_UOpsSymType *value; _Py_UOpsSymType *res; - value = stack_pointer[-1]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-1] = res; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _TO_BOOL_BOOL: { + break; } case _TO_BOOL_INT: { - _Py_UOpsSymType *value; _Py_UOpsSymType *res; - value = stack_pointer[-1]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-1] = res; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _TO_BOOL_LIST: { - _Py_UOpsSymType *value; _Py_UOpsSymType *res; - value = stack_pointer[-1]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-1] = res; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _TO_BOOL_NONE: { - _Py_UOpsSymType *value; _Py_UOpsSymType *res; - value = stack_pointer[-1]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-1] = res; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _TO_BOOL_STR: { - _Py_UOpsSymType *value; _Py_UOpsSymType *res; - value = stack_pointer[-1]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-1] = res; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _TO_BOOL_ALWAYS_TRUE: { - _Py_UOpsSymType *value; _Py_UOpsSymType *res; - value = stack_pointer[-1]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-1] = res; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _UNARY_INVERT: { - _Py_UOpsSymType *value; _Py_UOpsSymType *res; - value = stack_pointer[-1]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-1] = res; + + stack_pointer[0] = res; + stack_pointer += 1; break; } @@ -195,19 +194,18 @@ sym_matches_type(right, PYLONG_TYPE, 0)) { REPLACE_OP(_NOP, 0, 0); } + sym_set_type(left, PYLONG_TYPE, 0); + sym_set_type(right, PYLONG_TYPE, 0); break; } case _BINARY_OP_MULTIPLY_INT: { - _Py_UOpsSymType *right; - _Py_UOpsSymType *left; _Py_UOpsSymType *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2] = res; - stack_pointer += -1; + + stack_pointer[0] = res; + stack_pointer += 1; break; } @@ -224,21 +222,19 @@ if (res == NULL) { goto error; } + sym_set_type(res, PYLONG_TYPE, 0); stack_pointer[-2] = res; stack_pointer += -1; break; } case _BINARY_OP_SUBTRACT_INT: { - _Py_UOpsSymType *right; - _Py_UOpsSymType *left; _Py_UOpsSymType *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2] = res; - stack_pointer += -1; + + stack_pointer[0] = res; + stack_pointer += 1; break; } @@ -251,246 +247,180 @@ sym_matches_type(right, PYFLOAT_TYPE, 0)) { REPLACE_OP(_NOP, 0 ,0); } + sym_set_type(left, PYFLOAT_TYPE, 0); + sym_set_type(right, PYFLOAT_TYPE, 0); break; } case _BINARY_OP_MULTIPLY_FLOAT: { - _Py_UOpsSymType *right; - _Py_UOpsSymType *left; _Py_UOpsSymType *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; res = sym_init_unknown(ctx); if (res == NULL) goto error; + sym_set_type(res, PYFLOAT_TYPE, 0); - stack_pointer[-2] = res; - stack_pointer += -1; + stack_pointer[0] = res; + stack_pointer += 1; break; } case _BINARY_OP_ADD_FLOAT: { - _Py_UOpsSymType *right; - _Py_UOpsSymType *left; _Py_UOpsSymType *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; res = sym_init_unknown(ctx); if (res == NULL) goto error; + sym_set_type(res, PYFLOAT_TYPE, 0); - stack_pointer[-2] = res; - stack_pointer += -1; + stack_pointer[0] = res; + stack_pointer += 1; break; } case _BINARY_OP_SUBTRACT_FLOAT: { - _Py_UOpsSymType *right; - _Py_UOpsSymType *left; _Py_UOpsSymType *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; res = sym_init_unknown(ctx); if (res == NULL) goto error; + sym_set_type(res, PYFLOAT_TYPE, 0); - stack_pointer[-2] = res; - stack_pointer += -1; + stack_pointer[0] = res; + stack_pointer += 1; break; } case _GUARD_BOTH_UNICODE: { - _Py_UOpsSymType *right; _Py_UOpsSymType *left; + _Py_UOpsSymType *right; right = stack_pointer[-1]; left = stack_pointer[-2]; + sym_set_type(left, PYUNICODE_TYPE, 0); sym_set_type(right, PYUNICODE_TYPE, 0); break; } case _BINARY_OP_ADD_UNICODE: { - _Py_UOpsSymType *right; - _Py_UOpsSymType *left; _Py_UOpsSymType *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; res = sym_init_unknown(ctx); if (res == NULL) goto error; + sym_set_type(res, PYUNICODE_TYPE, 0); - stack_pointer[-2] = res; - stack_pointer += -1; + stack_pointer[0] = res; + stack_pointer += 1; break; } case _BINARY_SUBSCR: { - _Py_UOpsSymType *sub; - _Py_UOpsSymType *container; _Py_UOpsSymType *res; - sub = stack_pointer[-1]; - container = stack_pointer[-2]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2] = res; - stack_pointer += -1; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _BINARY_SLICE: { - _Py_UOpsSymType *stop; - _Py_UOpsSymType *start; - _Py_UOpsSymType *container; _Py_UOpsSymType *res; - stop = stack_pointer[-1]; - start = stack_pointer[-2]; - container = stack_pointer[-3]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-3] = res; - stack_pointer += -2; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _STORE_SLICE: { - _Py_UOpsSymType *stop; - _Py_UOpsSymType *start; - _Py_UOpsSymType *container; - _Py_UOpsSymType *v; - stop = stack_pointer[-1]; - start = stack_pointer[-2]; - container = stack_pointer[-3]; - v = stack_pointer[-4]; - stack_pointer += -4; + break; } case _BINARY_SUBSCR_LIST_INT: { - _Py_UOpsSymType *sub; - _Py_UOpsSymType *list; _Py_UOpsSymType *res; - sub = stack_pointer[-1]; - list = stack_pointer[-2]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2] = res; - stack_pointer += -1; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _BINARY_SUBSCR_STR_INT: { - _Py_UOpsSymType *sub; - _Py_UOpsSymType *str; _Py_UOpsSymType *res; - sub = stack_pointer[-1]; - str = stack_pointer[-2]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2] = res; - stack_pointer += -1; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _BINARY_SUBSCR_TUPLE_INT: { - _Py_UOpsSymType *sub; - _Py_UOpsSymType *tuple; _Py_UOpsSymType *res; - sub = stack_pointer[-1]; - tuple = stack_pointer[-2]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2] = res; - stack_pointer += -1; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _BINARY_SUBSCR_DICT: { - _Py_UOpsSymType *sub; - _Py_UOpsSymType *dict; _Py_UOpsSymType *res; - sub = stack_pointer[-1]; - dict = stack_pointer[-2]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2] = res; - stack_pointer += -1; + + stack_pointer[0] = res; + stack_pointer += 1; break; } /* _BINARY_SUBSCR_GETITEM is not a viable micro-op for tier 2 */ case _LIST_APPEND: { - _Py_UOpsSymType *v; - v = stack_pointer[-1]; - stack_pointer += -1; + break; } case _SET_ADD: { - _Py_UOpsSymType *v; - v = stack_pointer[-1]; - stack_pointer += -1; + break; } case _STORE_SUBSCR: { - _Py_UOpsSymType *sub; - _Py_UOpsSymType *container; - _Py_UOpsSymType *v; - sub = stack_pointer[-1]; - container = stack_pointer[-2]; - v = stack_pointer[-3]; - stack_pointer += -3; + break; } case _STORE_SUBSCR_LIST_INT: { - _Py_UOpsSymType *sub; - _Py_UOpsSymType *list; - _Py_UOpsSymType *value; - sub = stack_pointer[-1]; - list = stack_pointer[-2]; - value = stack_pointer[-3]; - stack_pointer += -3; + break; } case _STORE_SUBSCR_DICT: { - _Py_UOpsSymType *sub; - _Py_UOpsSymType *dict; - _Py_UOpsSymType *value; - sub = stack_pointer[-1]; - dict = stack_pointer[-2]; - value = stack_pointer[-3]; - stack_pointer += -3; + break; } case _DELETE_SUBSCR: { - _Py_UOpsSymType *sub; - _Py_UOpsSymType *container; - sub = stack_pointer[-1]; - container = stack_pointer[-2]; - stack_pointer += -2; + break; } case _CALL_INTRINSIC_1: { - _Py_UOpsSymType *value; _Py_UOpsSymType *res; - value = stack_pointer[-1]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-1] = res; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _CALL_INTRINSIC_2: { - _Py_UOpsSymType *value1; - _Py_UOpsSymType *value2; _Py_UOpsSymType *res; - value1 = stack_pointer[-1]; - value2 = stack_pointer[-2]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2] = res; - stack_pointer += -1; + + stack_pointer[0] = res; + stack_pointer += 1; break; } @@ -513,12 +443,12 @@ /* _INSTRUMENTED_RETURN_CONST is not a viable micro-op for tier 2 */ case _GET_AITER: { - _Py_UOpsSymType *obj; _Py_UOpsSymType *iter; - obj = stack_pointer[-1]; iter = sym_init_unknown(ctx); if (iter == NULL) goto error; - stack_pointer[-1] = iter; + + stack_pointer[0] = iter; + stack_pointer += 1; break; } @@ -526,18 +456,19 @@ _Py_UOpsSymType *awaitable; awaitable = sym_init_unknown(ctx); if (awaitable == NULL) goto error; + stack_pointer[0] = awaitable; stack_pointer += 1; break; } case _GET_AWAITABLE: { - _Py_UOpsSymType *iterable; _Py_UOpsSymType *iter; - iterable = stack_pointer[-1]; iter = sym_init_unknown(ctx); if (iter == NULL) goto error; - stack_pointer[-1] = iter; + + stack_pointer[0] = iter; + stack_pointer += 1; break; } @@ -548,9 +479,7 @@ /* _INSTRUMENTED_YIELD_VALUE is not a viable micro-op for tier 2 */ case _POP_EXCEPT: { - _Py_UOpsSymType *exc_value; - exc_value = stack_pointer[-1]; - stack_pointer += -1; + break; } @@ -558,6 +487,7 @@ _Py_UOpsSymType *value; value = sym_init_unknown(ctx); if (value == NULL) goto error; + stack_pointer[0] = value; stack_pointer += 1; break; @@ -567,65 +497,72 @@ _Py_UOpsSymType *bc; bc = sym_init_unknown(ctx); if (bc == NULL) goto error; + stack_pointer[0] = bc; stack_pointer += 1; break; } case _STORE_NAME: { - _Py_UOpsSymType *v; - v = stack_pointer[-1]; - stack_pointer += -1; + break; } case _DELETE_NAME: { + break; } case _UNPACK_SEQUENCE: { _Py_UOpsSymType *seq; + _Py_UOpsSymType **values; seq = stack_pointer[-1]; + values = &stack_pointer[-1]; + /* This has to be done manually */ + (void)seq; + for (int i = 0; i < oparg; i++) { + values[i] = sym_init_unknown(ctx); + if (values[i] == NULL) { + goto error; + } + } stack_pointer += -1 + oparg; break; } case _UNPACK_SEQUENCE_TWO_TUPLE: { - _Py_UOpsSymType *seq; _Py_UOpsSymType **values; - seq = stack_pointer[-1]; - values = &stack_pointer[-1]; + values = &stack_pointer[0]; for (int _i = oparg; --_i >= 0;) { values[_i] = sym_init_unknown(ctx); if (values[_i] == NULL) goto error; } - stack_pointer += -1 + oparg; + + stack_pointer += oparg; break; } case _UNPACK_SEQUENCE_TUPLE: { - _Py_UOpsSymType *seq; _Py_UOpsSymType **values; - seq = stack_pointer[-1]; - values = &stack_pointer[-1]; + values = &stack_pointer[0]; for (int _i = oparg; --_i >= 0;) { values[_i] = sym_init_unknown(ctx); if (values[_i] == NULL) goto error; } - stack_pointer += -1 + oparg; + + stack_pointer += oparg; break; } case _UNPACK_SEQUENCE_LIST: { - _Py_UOpsSymType *seq; _Py_UOpsSymType **values; - seq = stack_pointer[-1]; - values = &stack_pointer[-1]; + values = &stack_pointer[0]; for (int _i = oparg; --_i >= 0;) { values[_i] = sym_init_unknown(ctx); if (values[_i] == NULL) goto error; } - stack_pointer += -1 + oparg; + + stack_pointer += oparg; break; } @@ -635,6 +572,7 @@ seq = stack_pointer[-1]; values = &stack_pointer[-1]; /* This has to be done manually */ + (void)seq; int totalargs = (oparg & 0xFF) + (oparg >> 8) + 1; for (int i = 0; i < totalargs; i++) { values[i] = sym_init_unknown(ctx); @@ -647,29 +585,22 @@ } case _STORE_ATTR: { - _Py_UOpsSymType *owner; - _Py_UOpsSymType *v; - owner = stack_pointer[-1]; - v = stack_pointer[-2]; - stack_pointer += -2; + break; } case _DELETE_ATTR: { - _Py_UOpsSymType *owner; - owner = stack_pointer[-1]; - stack_pointer += -1; + break; } case _STORE_GLOBAL: { - _Py_UOpsSymType *v; - v = stack_pointer[-1]; - stack_pointer += -1; + break; } case _DELETE_GLOBAL: { + break; } @@ -677,18 +608,19 @@ _Py_UOpsSymType *locals; locals = sym_init_unknown(ctx); if (locals == NULL) goto error; + stack_pointer[0] = locals; stack_pointer += 1; break; } case _LOAD_FROM_DICT_OR_GLOBALS: { - _Py_UOpsSymType *mod_or_class_dict; _Py_UOpsSymType *v; - mod_or_class_dict = stack_pointer[-1]; v = sym_init_unknown(ctx); if (v == NULL) goto error; - stack_pointer[-1] = v; + + stack_pointer[0] = v; + stack_pointer += 1; break; } @@ -696,6 +628,7 @@ _Py_UOpsSymType *v; v = sym_init_unknown(ctx); if (v == NULL) goto error; + stack_pointer[0] = v; stack_pointer += 1; break; @@ -709,6 +642,7 @@ if (res == NULL) goto error; null = sym_init_unknown(ctx); if (null == NULL) goto error; + stack_pointer[0] = res; if (oparg & 1) stack_pointer[1] = null; stack_pointer += 1 + (oparg & 1); @@ -716,10 +650,12 @@ } case _GUARD_GLOBALS_VERSION: { + break; } case _GUARD_BUILTINS_VERSION: { + break; } @@ -731,6 +667,7 @@ if (res == NULL) goto error; null = sym_init_unknown(ctx); if (null == NULL) goto error; + stack_pointer[0] = res; if (oparg & 1) stack_pointer[1] = null; stack_pointer += 1 + (oparg & 1); @@ -745,6 +682,7 @@ if (res == NULL) goto error; null = sym_init_unknown(ctx); if (null == NULL) goto error; + stack_pointer[0] = res; if (oparg & 1) stack_pointer[1] = null; stack_pointer += 1 + (oparg & 1); @@ -752,24 +690,27 @@ } case _DELETE_FAST: { + break; } case _MAKE_CELL: { + break; } case _DELETE_DEREF: { + break; } case _LOAD_FROM_DICT_OR_DEREF: { - _Py_UOpsSymType *class_dict; _Py_UOpsSymType *value; - class_dict = stack_pointer[-1]; value = sym_init_unknown(ctx); if (value == NULL) goto error; - stack_pointer[-1] = value; + + stack_pointer[0] = value; + stack_pointer += 1; break; } @@ -777,181 +718,152 @@ _Py_UOpsSymType *value; value = sym_init_unknown(ctx); if (value == NULL) goto error; + stack_pointer[0] = value; stack_pointer += 1; break; } case _STORE_DEREF: { - _Py_UOpsSymType *v; - v = stack_pointer[-1]; - stack_pointer += -1; + break; } case _COPY_FREE_VARS: { + break; } case _BUILD_STRING: { - _Py_UOpsSymType **pieces; _Py_UOpsSymType *str; - pieces = &stack_pointer[-oparg]; str = sym_init_unknown(ctx); if (str == NULL) goto error; - stack_pointer[-oparg] = str; - stack_pointer += 1 - oparg; + + stack_pointer[0] = str; + stack_pointer += 1; break; } case _BUILD_TUPLE: { - _Py_UOpsSymType **values; _Py_UOpsSymType *tup; - values = &stack_pointer[-oparg]; tup = sym_init_unknown(ctx); if (tup == NULL) goto error; - stack_pointer[-oparg] = tup; - stack_pointer += 1 - oparg; + + stack_pointer[0] = tup; + stack_pointer += 1; break; } case _BUILD_LIST: { - _Py_UOpsSymType **values; _Py_UOpsSymType *list; - values = &stack_pointer[-oparg]; list = sym_init_unknown(ctx); if (list == NULL) goto error; - stack_pointer[-oparg] = list; - stack_pointer += 1 - oparg; + + stack_pointer[0] = list; + stack_pointer += 1; break; } case _LIST_EXTEND: { - _Py_UOpsSymType *iterable; - iterable = stack_pointer[-1]; - stack_pointer += -1; + break; } case _SET_UPDATE: { - _Py_UOpsSymType *iterable; - iterable = stack_pointer[-1]; - stack_pointer += -1; + break; } case _BUILD_SET: { - _Py_UOpsSymType **values; _Py_UOpsSymType *set; - values = &stack_pointer[-oparg]; set = sym_init_unknown(ctx); if (set == NULL) goto error; - stack_pointer[-oparg] = set; - stack_pointer += 1 - oparg; + + stack_pointer[0] = set; + stack_pointer += 1; break; } case _BUILD_MAP: { - _Py_UOpsSymType **values; _Py_UOpsSymType *map; - values = &stack_pointer[-oparg*2]; map = sym_init_unknown(ctx); if (map == NULL) goto error; - stack_pointer[-oparg*2] = map; - stack_pointer += 1 - oparg*2; + + stack_pointer[0] = map; + stack_pointer += 1; break; } case _SETUP_ANNOTATIONS: { + break; } case _BUILD_CONST_KEY_MAP: { - _Py_UOpsSymType *keys; - _Py_UOpsSymType **values; _Py_UOpsSymType *map; - keys = stack_pointer[-1]; - values = &stack_pointer[-1 - oparg]; map = sym_init_unknown(ctx); if (map == NULL) goto error; - stack_pointer[-1 - oparg] = map; - stack_pointer += -oparg; + + stack_pointer[0] = map; + stack_pointer += 1; break; } case _DICT_UPDATE: { - _Py_UOpsSymType *update; - update = stack_pointer[-1]; - stack_pointer += -1; + break; } case _DICT_MERGE: { - _Py_UOpsSymType *update; - update = stack_pointer[-1]; - stack_pointer += -1; + break; } case _MAP_ADD: { - _Py_UOpsSymType *value; - _Py_UOpsSymType *key; - value = stack_pointer[-1]; - key = stack_pointer[-2]; - stack_pointer += -2; + break; } /* _INSTRUMENTED_LOAD_SUPER_ATTR is not a viable micro-op for tier 2 */ case _LOAD_SUPER_ATTR_ATTR: { - _Py_UOpsSymType *self; - _Py_UOpsSymType *class; - _Py_UOpsSymType *global_super; _Py_UOpsSymType *attr; - self = stack_pointer[-1]; - class = stack_pointer[-2]; - global_super = stack_pointer[-3]; attr = sym_init_unknown(ctx); if (attr == NULL) goto error; - stack_pointer[-3] = attr; - stack_pointer += -2 + ((0) ? 1 : 0); + + stack_pointer[0] = attr; + stack_pointer += 1 + ((0) ? 1 : 0); break; } case _LOAD_SUPER_ATTR_METHOD: { - _Py_UOpsSymType *self; - _Py_UOpsSymType *class; - _Py_UOpsSymType *global_super; _Py_UOpsSymType *attr; _Py_UOpsSymType *self_or_null; - self = stack_pointer[-1]; - class = stack_pointer[-2]; - global_super = stack_pointer[-3]; attr = sym_init_unknown(ctx); if (attr == NULL) goto error; self_or_null = sym_init_unknown(ctx); if (self_or_null == NULL) goto error; - stack_pointer[-3] = attr; - stack_pointer[-2] = self_or_null; - stack_pointer += -1; + + stack_pointer[0] = attr; + stack_pointer[1] = self_or_null; + stack_pointer += 2; break; } case _LOAD_ATTR: { - _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *self_or_null = sym_init_null(ctx); if(self_or_null) {goto error;} - owner = stack_pointer[-1]; attr = sym_init_unknown(ctx); if (attr == NULL) goto error; self_or_null = sym_init_unknown(ctx); if (self_or_null == NULL) goto error; + + (void)attr; sym_set_type(self_or_null, SELF_OR_NULL, 0); - stack_pointer[-1] = attr; - if (oparg & 1) stack_pointer[0] = self_or_null; - stack_pointer += (oparg & 1); + stack_pointer[0] = attr; + if (oparg & 1) stack_pointer[1] = self_or_null; + stack_pointer += 1 + (oparg & 1); break; } @@ -959,103 +871,103 @@ _Py_UOpsSymType *owner; owner = stack_pointer[-1]; uint32_t type_version = (uint32_t)inst->operand; + sym_set_type(owner, GUARD_TYPE_VERSION_TYPE, type_version); break; } case _CHECK_MANAGED_OBJECT_HAS_VALUES: { + break; } case _LOAD_ATTR_INSTANCE_VALUE: { - _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *null = sym_init_null(ctx); if(null) {goto error;} - owner = stack_pointer[-1]; attr = sym_init_unknown(ctx); if (attr == NULL) goto error; null = sym_init_unknown(ctx); if (null == NULL) goto error; - stack_pointer[-1] = attr; - if (oparg & 1) stack_pointer[0] = null; - stack_pointer += (oparg & 1); + + stack_pointer[0] = attr; + if (oparg & 1) stack_pointer[1] = null; + stack_pointer += 1 + (oparg & 1); break; } case _CHECK_ATTR_MODULE: { + break; } case _LOAD_ATTR_MODULE: { - _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *null = sym_init_null(ctx); if(null) {goto error;} - owner = stack_pointer[-1]; attr = sym_init_unknown(ctx); if (attr == NULL) goto error; null = sym_init_unknown(ctx); if (null == NULL) goto error; - stack_pointer[-1] = attr; - if (oparg & 1) stack_pointer[0] = null; - stack_pointer += (oparg & 1); + + stack_pointer[0] = attr; + if (oparg & 1) stack_pointer[1] = null; + stack_pointer += 1 + (oparg & 1); break; } case _CHECK_ATTR_WITH_HINT: { + break; } case _LOAD_ATTR_WITH_HINT: { - _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *null = sym_init_null(ctx); if(null) {goto error;} - owner = stack_pointer[-1]; attr = sym_init_unknown(ctx); if (attr == NULL) goto error; null = sym_init_unknown(ctx); if (null == NULL) goto error; - stack_pointer[-1] = attr; - if (oparg & 1) stack_pointer[0] = null; - stack_pointer += (oparg & 1); + + stack_pointer[0] = attr; + if (oparg & 1) stack_pointer[1] = null; + stack_pointer += 1 + (oparg & 1); break; } case _LOAD_ATTR_SLOT: { - _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *null = sym_init_null(ctx); if(null) {goto error;} - owner = stack_pointer[-1]; attr = sym_init_unknown(ctx); if (attr == NULL) goto error; null = sym_init_unknown(ctx); if (null == NULL) goto error; - stack_pointer[-1] = attr; - if (oparg & 1) stack_pointer[0] = null; - stack_pointer += (oparg & 1); + + stack_pointer[0] = attr; + if (oparg & 1) stack_pointer[1] = null; + stack_pointer += 1 + (oparg & 1); break; } case _CHECK_ATTR_CLASS: { + break; } case _LOAD_ATTR_CLASS: { - _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *null = sym_init_null(ctx); if(null) {goto error;} - owner = stack_pointer[-1]; attr = sym_init_unknown(ctx); if (attr == NULL) goto error; null = sym_init_unknown(ctx); if (null == NULL) goto error; - stack_pointer[-1] = attr; - if (oparg & 1) stack_pointer[0] = null; - stack_pointer += (oparg & 1); + + stack_pointer[0] = attr; + if (oparg & 1) stack_pointer[1] = null; + stack_pointer += 1 + (oparg & 1); break; } @@ -1066,131 +978,104 @@ case _GUARD_DORV_VALUES: { _Py_UOpsSymType *owner; owner = stack_pointer[-1]; + sym_set_type(owner, GUARD_DORV_VALUES_TYPE, 0); break; } case _STORE_ATTR_INSTANCE_VALUE: { - _Py_UOpsSymType *owner; - _Py_UOpsSymType *value; - owner = stack_pointer[-1]; - value = stack_pointer[-2]; - stack_pointer += -2; + break; } /* _STORE_ATTR_WITH_HINT is not a viable micro-op for tier 2 */ case _STORE_ATTR_SLOT: { - _Py_UOpsSymType *owner; - _Py_UOpsSymType *value; - owner = stack_pointer[-1]; - value = stack_pointer[-2]; - stack_pointer += -2; + break; } case _COMPARE_OP: { - _Py_UOpsSymType *right; - _Py_UOpsSymType *left; _Py_UOpsSymType *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2] = res; - stack_pointer += -1; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _COMPARE_OP_FLOAT: { - _Py_UOpsSymType *right; - _Py_UOpsSymType *left; _Py_UOpsSymType *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2] = res; - stack_pointer += -1; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _COMPARE_OP_INT: { - _Py_UOpsSymType *right; - _Py_UOpsSymType *left; _Py_UOpsSymType *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2] = res; - stack_pointer += -1; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _COMPARE_OP_STR: { - _Py_UOpsSymType *right; - _Py_UOpsSymType *left; _Py_UOpsSymType *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2] = res; - stack_pointer += -1; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _IS_OP: { - _Py_UOpsSymType *right; - _Py_UOpsSymType *left; _Py_UOpsSymType *b; - right = stack_pointer[-1]; - left = stack_pointer[-2]; b = sym_init_unknown(ctx); if (b == NULL) goto error; - stack_pointer[-2] = b; - stack_pointer += -1; + + stack_pointer[0] = b; + stack_pointer += 1; break; } case _CONTAINS_OP: { - _Py_UOpsSymType *right; - _Py_UOpsSymType *left; _Py_UOpsSymType *b; - right = stack_pointer[-1]; - left = stack_pointer[-2]; b = sym_init_unknown(ctx); if (b == NULL) goto error; - stack_pointer[-2] = b; - stack_pointer += -1; + + stack_pointer[0] = b; + stack_pointer += 1; break; } case _CHECK_EG_MATCH: { - _Py_UOpsSymType *match_type; - _Py_UOpsSymType *exc_value; _Py_UOpsSymType *rest; _Py_UOpsSymType *match; - match_type = stack_pointer[-1]; - exc_value = stack_pointer[-2]; rest = sym_init_unknown(ctx); if (rest == NULL) goto error; match = sym_init_unknown(ctx); if (match == NULL) goto error; - stack_pointer[-2] = rest; - stack_pointer[-1] = match; + + stack_pointer[0] = rest; + stack_pointer[1] = match; + stack_pointer += 2; break; } case _CHECK_EXC_MATCH: { - _Py_UOpsSymType *right; _Py_UOpsSymType *b; - right = stack_pointer[-1]; b = sym_init_unknown(ctx); if (b == NULL) goto error; - stack_pointer[-1] = b; + + stack_pointer[0] = b; + stack_pointer += 1; break; } @@ -1201,12 +1086,12 @@ /* _POP_JUMP_IF_TRUE is not a viable micro-op for tier 2 */ case _IS_NONE: { - _Py_UOpsSymType *value; _Py_UOpsSymType *b; - value = stack_pointer[-1]; b = sym_init_unknown(ctx); if (b == NULL) goto error; - stack_pointer[-1] = b; + + stack_pointer[0] = b; + stack_pointer += 1; break; } @@ -1214,23 +1099,19 @@ _Py_UOpsSymType *len_o; len_o = sym_init_unknown(ctx); if (len_o == NULL) goto error; + stack_pointer[0] = len_o; stack_pointer += 1; break; } case _MATCH_CLASS: { - _Py_UOpsSymType *names; - _Py_UOpsSymType *type; - _Py_UOpsSymType *subject; _Py_UOpsSymType *attrs; - names = stack_pointer[-1]; - type = stack_pointer[-2]; - subject = stack_pointer[-3]; attrs = sym_init_unknown(ctx); if (attrs == NULL) goto error; - stack_pointer[-3] = attrs; - stack_pointer += -2; + + stack_pointer[0] = attrs; + stack_pointer += 1; break; } @@ -1238,6 +1119,7 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; + stack_pointer[0] = res; stack_pointer += 1; break; @@ -1247,6 +1129,7 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; + stack_pointer[0] = res; stack_pointer += 1; break; @@ -1256,28 +1139,29 @@ _Py_UOpsSymType *values_or_none; values_or_none = sym_init_unknown(ctx); if (values_or_none == NULL) goto error; + stack_pointer[0] = values_or_none; stack_pointer += 1; break; } case _GET_ITER: { - _Py_UOpsSymType *iterable; _Py_UOpsSymType *iter; - iterable = stack_pointer[-1]; iter = sym_init_unknown(ctx); if (iter == NULL) goto error; - stack_pointer[-1] = iter; + + stack_pointer[0] = iter; + stack_pointer += 1; break; } case _GET_YIELD_FROM_ITER: { - _Py_UOpsSymType *iterable; _Py_UOpsSymType *iter; - iterable = stack_pointer[-1]; iter = sym_init_unknown(ctx); if (iter == NULL) goto error; - stack_pointer[-1] = iter; + + stack_pointer[0] = iter; + stack_pointer += 1; break; } @@ -1287,6 +1171,7 @@ _Py_UOpsSymType *next; next = sym_init_unknown(ctx); if (next == NULL) goto error; + stack_pointer[0] = next; stack_pointer += 1; break; @@ -1295,12 +1180,14 @@ /* _INSTRUMENTED_FOR_ITER is not a viable micro-op for tier 2 */ case _ITER_CHECK_LIST: { + break; } /* _ITER_JUMP_LIST is not a viable micro-op for tier 2 */ case _GUARD_NOT_EXHAUSTED_LIST: { + break; } @@ -1308,18 +1195,21 @@ _Py_UOpsSymType *next; next = sym_init_unknown(ctx); if (next == NULL) goto error; + stack_pointer[0] = next; stack_pointer += 1; break; } case _ITER_CHECK_TUPLE: { + break; } /* _ITER_JUMP_TUPLE is not a viable micro-op for tier 2 */ case _GUARD_NOT_EXHAUSTED_TUPLE: { + break; } @@ -1327,18 +1217,21 @@ _Py_UOpsSymType *next; next = sym_init_unknown(ctx); if (next == NULL) goto error; + stack_pointer[0] = next; stack_pointer += 1; break; } case _ITER_CHECK_RANGE: { + break; } /* _ITER_JUMP_RANGE is not a viable micro-op for tier 2 */ case _GUARD_NOT_EXHAUSTED_RANGE: { + break; } @@ -1348,6 +1241,8 @@ iter = stack_pointer[-1]; next = sym_init_unknown(ctx); if (next == NULL) goto error; + + (void)iter; sym_set_type(next, PYLONG_TYPE, 0); stack_pointer[0] = next; stack_pointer += 1; @@ -1357,32 +1252,30 @@ /* _FOR_ITER_GEN is not a viable micro-op for tier 2 */ case _BEFORE_ASYNC_WITH: { - _Py_UOpsSymType *mgr; _Py_UOpsSymType *exit; _Py_UOpsSymType *res; - mgr = stack_pointer[-1]; exit = sym_init_unknown(ctx); if (exit == NULL) goto error; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-1] = exit; - stack_pointer[0] = res; - stack_pointer += 1; + + stack_pointer[0] = exit; + stack_pointer[1] = res; + stack_pointer += 2; break; } case _BEFORE_WITH: { - _Py_UOpsSymType *mgr; _Py_UOpsSymType *exit; _Py_UOpsSymType *res; - mgr = stack_pointer[-1]; exit = sym_init_unknown(ctx); if (exit == NULL) goto error; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-1] = exit; - stack_pointer[0] = res; - stack_pointer += 1; + + stack_pointer[0] = exit; + stack_pointer[1] = res; + stack_pointer += 2; break; } @@ -1390,26 +1283,28 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; + stack_pointer[0] = res; stack_pointer += 1; break; } case _PUSH_EXC_INFO: { - _Py_UOpsSymType *new_exc; _Py_UOpsSymType *prev_exc; - new_exc = stack_pointer[-1]; + _Py_UOpsSymType *new_exc; prev_exc = sym_init_unknown(ctx); if (prev_exc == NULL) goto error; new_exc = sym_init_unknown(ctx); if (new_exc == NULL) goto error; - stack_pointer[-1] = prev_exc; - stack_pointer[0] = new_exc; - stack_pointer += 1; + + stack_pointer[0] = prev_exc; + stack_pointer[1] = new_exc; + stack_pointer += 2; break; } case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT: { + break; } @@ -1417,81 +1312,78 @@ _Py_UOpsSymType *owner; owner = stack_pointer[-1]; uint32_t keys_version = (uint32_t)inst->operand; + sym_set_type(owner, GUARD_KEYS_VERSION_TYPE, keys_version); break; } case _LOAD_ATTR_METHOD_WITH_VALUES: { - _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *self = sym_init_null(ctx); if(self) {goto error;} - owner = stack_pointer[-1]; attr = sym_init_unknown(ctx); if (attr == NULL) goto error; self = sym_init_unknown(ctx); if (self == NULL) goto error; - stack_pointer[-1] = attr; - if (1) stack_pointer[0] = self; - stack_pointer += ((1) ? 1 : 0); + + stack_pointer[0] = attr; + if (1) stack_pointer[1] = self; + stack_pointer += 1 + ((1) ? 1 : 0); break; } case _LOAD_ATTR_METHOD_NO_DICT: { - _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *self = sym_init_null(ctx); if(self) {goto error;} - owner = stack_pointer[-1]; attr = sym_init_unknown(ctx); if (attr == NULL) goto error; self = sym_init_unknown(ctx); if (self == NULL) goto error; - stack_pointer[-1] = attr; - if (1) stack_pointer[0] = self; - stack_pointer += ((1) ? 1 : 0); + + stack_pointer[0] = attr; + if (1) stack_pointer[1] = self; + stack_pointer += 1 + ((1) ? 1 : 0); break; } case _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: { - _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; - owner = stack_pointer[-1]; attr = sym_init_unknown(ctx); if (attr == NULL) goto error; - stack_pointer[-1] = attr; - stack_pointer += ((0) ? 1 : 0); + + stack_pointer[0] = attr; + stack_pointer += 1 + ((0) ? 1 : 0); break; } case _LOAD_ATTR_NONDESCRIPTOR_NO_DICT: { - _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; - owner = stack_pointer[-1]; attr = sym_init_unknown(ctx); if (attr == NULL) goto error; - stack_pointer[-1] = attr; - stack_pointer += ((0) ? 1 : 0); + + stack_pointer[0] = attr; + stack_pointer += 1 + ((0) ? 1 : 0); break; } case _CHECK_ATTR_METHOD_LAZY_DICT: { + break; } case _LOAD_ATTR_METHOD_LAZY_DICT: { - _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *self = sym_init_null(ctx); if(self) {goto error;} - owner = stack_pointer[-1]; attr = sym_init_unknown(ctx); if (attr == NULL) goto error; self = sym_init_unknown(ctx); if (self == NULL) goto error; - stack_pointer[-1] = attr; - if (1) stack_pointer[0] = self; - stack_pointer += ((1) ? 1 : 0); + + stack_pointer[0] = attr; + if (1) stack_pointer[1] = self; + stack_pointer += 1 + ((1) ? 1 : 0); break; } @@ -1500,26 +1392,27 @@ /* _CALL is not a viable micro-op for tier 2 */ case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: { - _Py_UOpsSymType *null; _Py_UOpsSymType *callable; + _Py_UOpsSymType *null; null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; + sym_set_type(callable, PYMETHOD_TYPE, 0); sym_set_type(null, NULL_TYPE, 0); break; } case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: { - _Py_UOpsSymType *callable; _Py_UOpsSymType *func; _Py_UOpsSymType *self; - callable = stack_pointer[-2]; func = sym_init_unknown(ctx); if (func == NULL) goto error; self = sym_init_unknown(ctx); if (self == NULL) goto error; - stack_pointer[-2] = func; - stack_pointer[-1] = self; + + stack_pointer[0] = func; + stack_pointer[1] = self; + stack_pointer += 2; break; } @@ -1533,16 +1426,19 @@ } case _CHECK_FUNCTION_EXACT_ARGS: { - _Py_UOpsSymType *self_or_null; _Py_UOpsSymType *callable; + _Py_UOpsSymType *self_or_null; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; uint32_t func_version = (uint32_t)inst->operand; + sym_set_type(callable, PYFUNCTION_TYPE_VERSION_TYPE, func_version); + (void)self_or_null; break; } case _CHECK_STACK_SPACE: { + break; } @@ -1582,7 +1478,7 @@ if (new_frame == NULL){ goto error; } - stack_pointer[-2 - oparg] = (PyObject *)new_frame; + stack_pointer[-2 - oparg] = (_Py_UOpsSymType *)new_frame; stack_pointer += -1 - oparg; break; } @@ -1602,206 +1498,139 @@ /* _CALL_PY_WITH_DEFAULTS is not a viable micro-op for tier 2 */ case _CALL_TYPE_1: { - _Py_UOpsSymType **args; - _Py_UOpsSymType *null; - _Py_UOpsSymType *callable; _Py_UOpsSymType *res; - args = &stack_pointer[-oparg]; - null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _CALL_STR_1: { - _Py_UOpsSymType **args; - _Py_UOpsSymType *null; - _Py_UOpsSymType *callable; _Py_UOpsSymType *res; - args = &stack_pointer[-oparg]; - null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _CALL_TUPLE_1: { - _Py_UOpsSymType **args; - _Py_UOpsSymType *null; - _Py_UOpsSymType *callable; _Py_UOpsSymType *res; - args = &stack_pointer[-oparg]; - null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; + + stack_pointer[0] = res; + stack_pointer += 1; break; } /* _CALL_ALLOC_AND_ENTER_INIT is not a viable micro-op for tier 2 */ case _EXIT_INIT_CHECK: { - _Py_UOpsSymType *should_be_none; - should_be_none = stack_pointer[-1]; - stack_pointer += -1; + break; } case _CALL_BUILTIN_CLASS: { - _Py_UOpsSymType **args; - _Py_UOpsSymType *self_or_null; - _Py_UOpsSymType *callable; _Py_UOpsSymType *res; - args = &stack_pointer[-oparg]; - self_or_null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _CALL_BUILTIN_O: { - _Py_UOpsSymType **args; - _Py_UOpsSymType *self_or_null; - _Py_UOpsSymType *callable; _Py_UOpsSymType *res; - args = &stack_pointer[-oparg]; - self_or_null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _CALL_BUILTIN_FAST: { - _Py_UOpsSymType **args; - _Py_UOpsSymType *self_or_null; - _Py_UOpsSymType *callable; _Py_UOpsSymType *res; - args = &stack_pointer[-oparg]; - self_or_null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _CALL_BUILTIN_FAST_WITH_KEYWORDS: { - _Py_UOpsSymType **args; - _Py_UOpsSymType *self_or_null; - _Py_UOpsSymType *callable; _Py_UOpsSymType *res; - args = &stack_pointer[-oparg]; - self_or_null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _CALL_LEN: { - _Py_UOpsSymType **args; - _Py_UOpsSymType *self_or_null; - _Py_UOpsSymType *callable; _Py_UOpsSymType *res; - args = &stack_pointer[-oparg]; - self_or_null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _CALL_ISINSTANCE: { - _Py_UOpsSymType **args; - _Py_UOpsSymType *self_or_null; - _Py_UOpsSymType *callable; _Py_UOpsSymType *res; - args = &stack_pointer[-oparg]; - self_or_null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _CALL_METHOD_DESCRIPTOR_O: { - _Py_UOpsSymType **args; - _Py_UOpsSymType *self_or_null; - _Py_UOpsSymType *callable; _Py_UOpsSymType *res; - args = &stack_pointer[-oparg]; - self_or_null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: { - _Py_UOpsSymType **args; - _Py_UOpsSymType *self_or_null; - _Py_UOpsSymType *callable; _Py_UOpsSymType *res; - args = &stack_pointer[-oparg]; - self_or_null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _CALL_METHOD_DESCRIPTOR_NOARGS: { - _Py_UOpsSymType **args; - _Py_UOpsSymType *self_or_null; - _Py_UOpsSymType *callable; _Py_UOpsSymType *res; - args = &stack_pointer[-oparg]; - self_or_null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _CALL_METHOD_DESCRIPTOR_FAST: { - _Py_UOpsSymType **args; - _Py_UOpsSymType *self_or_null; - _Py_UOpsSymType *callable; _Py_UOpsSymType *res; - args = &stack_pointer[-oparg]; - self_or_null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; + + stack_pointer[0] = res; + stack_pointer += 1; break; } @@ -1814,73 +1643,62 @@ /* _CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ case _MAKE_FUNCTION: { - _Py_UOpsSymType *codeobj; _Py_UOpsSymType *func; - codeobj = stack_pointer[-1]; func = sym_init_unknown(ctx); if (func == NULL) goto error; - stack_pointer[-1] = func; + + stack_pointer[0] = func; + stack_pointer += 1; break; } case _SET_FUNCTION_ATTRIBUTE: { _Py_UOpsSymType *func; - _Py_UOpsSymType *attr; - func = stack_pointer[-1]; - attr = stack_pointer[-2]; func = sym_init_unknown(ctx); if (func == NULL) goto error; - stack_pointer[-2] = func; - stack_pointer += -1; + + stack_pointer[0] = func; + stack_pointer += 1; break; } case _BUILD_SLICE: { - _Py_UOpsSymType *step = sym_init_null(ctx); - if(step) {goto error;} - _Py_UOpsSymType *stop; - _Py_UOpsSymType *start; _Py_UOpsSymType *slice; - if (oparg == 3) { step = stack_pointer[-((oparg == 3) ? 1 : 0)]; } - stop = stack_pointer[-1 - ((oparg == 3) ? 1 : 0)]; - start = stack_pointer[-2 - ((oparg == 3) ? 1 : 0)]; slice = sym_init_unknown(ctx); if (slice == NULL) goto error; - stack_pointer[-2 - ((oparg == 3) ? 1 : 0)] = slice; - stack_pointer += -1 - ((oparg == 3) ? 1 : 0); + + stack_pointer[0] = slice; + stack_pointer += 1; break; } case _CONVERT_VALUE: { - _Py_UOpsSymType *value; _Py_UOpsSymType *result; - value = stack_pointer[-1]; result = sym_init_unknown(ctx); if (result == NULL) goto error; - stack_pointer[-1] = result; + + stack_pointer[0] = result; + stack_pointer += 1; break; } case _FORMAT_SIMPLE: { - _Py_UOpsSymType *value; _Py_UOpsSymType *res; - value = stack_pointer[-1]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-1] = res; + + stack_pointer[0] = res; + stack_pointer += 1; break; } case _FORMAT_WITH_SPEC: { - _Py_UOpsSymType *fmt_spec; - _Py_UOpsSymType *value; _Py_UOpsSymType *res; - fmt_spec = stack_pointer[-1]; - value = stack_pointer[-2]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2] = res; - stack_pointer += -1; + + stack_pointer[0] = res; + stack_pointer += 1; break; } @@ -1896,15 +1714,12 @@ } case _BINARY_OP: { - _Py_UOpsSymType *rhs; - _Py_UOpsSymType *lhs; _Py_UOpsSymType *res; - rhs = stack_pointer[-1]; - lhs = stack_pointer[-2]; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[-2] = res; - stack_pointer += -1; + + stack_pointer[0] = res; + stack_pointer += 1; break; } @@ -1913,6 +1728,7 @@ _Py_UOpsSymType *bottom; top = stack_pointer[-1]; bottom = stack_pointer[-2 - (oparg-2)]; + stack_pointer[-2 - (oparg-2)] = top; stack_pointer[-1] = bottom; break; @@ -1933,65 +1749,64 @@ /* _INSTRUMENTED_POP_JUMP_IF_NOT_NONE is not a viable micro-op for tier 2 */ case _GUARD_IS_TRUE_POP: { - _Py_UOpsSymType *flag; - flag = stack_pointer[-1]; - stack_pointer += -1; + break; } case _GUARD_IS_FALSE_POP: { - _Py_UOpsSymType *flag; - flag = stack_pointer[-1]; - stack_pointer += -1; + break; } case _GUARD_IS_NONE_POP: { - _Py_UOpsSymType *val; - val = stack_pointer[-1]; - stack_pointer += -1; + break; } case _GUARD_IS_NOT_NONE_POP: { - _Py_UOpsSymType *val; - val = stack_pointer[-1]; - stack_pointer += -1; + break; } case _JUMP_TO_TOP: { + break; } case _SET_IP: { + break; } case _SAVE_RETURN_OFFSET: { + break; } case _EXIT_TRACE: { + break; } case _JUMP_ABSOLUTE: { + break; } case _JUMP_ABSOLUTE_HEADER: { + break; } case _CHECK_VALIDITY: { + break; } case _LOAD_CONST_INLINE: { _Py_UOpsSymType *value; PyObject *ptr = (PyObject *)inst->operand; - _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); + _Py_UOpsSymType *sym_const = sym_init_const(ctx, ptr); if (sym_const == NULL) { goto error; } @@ -2005,7 +1820,7 @@ case _LOAD_CONST_INLINE_BORROW: { _Py_UOpsSymType *value; PyObject *ptr = (PyObject *)inst->operand; - _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); + _Py_UOpsSymType *sym_const = sym_init_const(ctx, ptr); if (sym_const == NULL) { goto error; } @@ -2020,7 +1835,7 @@ _Py_UOpsSymType *value; _Py_UOpsSymType *null; PyObject *ptr = (PyObject *)inst->operand; - _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); + _Py_UOpsSymType *sym_const = sym_init_const(ctx, ptr); if (sym_const == NULL) { goto error; } @@ -2041,7 +1856,7 @@ _Py_UOpsSymType *value; _Py_UOpsSymType *null; PyObject *ptr = (PyObject *)inst->operand; - _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); + _Py_UOpsSymType *sym_const = sym_init_const(ctx, ptr); if (sym_const == NULL) { goto error; } @@ -2059,17 +1874,17 @@ } case _CHECK_GLOBALS: { + break; } case _CHECK_BUILTINS: { + break; } case _INTERNAL_INCREMENT_OPT_COUNTER: { - _Py_UOpsSymType *opt; - opt = stack_pointer[-1]; - stack_pointer += -1; + break; } diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 6384e09e8cab74..94da4f34da694f 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -498,6 +498,11 @@ op_is_bookkeeping(uint32_t opcode) { opcode == _RESUME_CHECK); } +static inline bool +op_is_data_movement_only(uint32_t opcode) { + return (opcode == _STORE_FAST || opcode == STORE_FAST_MAYBE_NULL); +} + static inline bool is_const(_Py_UOpsSymType *expr) @@ -575,35 +580,9 @@ uop_abstract_interpret_single_inst( ) { #define STACK_LEVEL() ((int)(stack_pointer - ctx->frame->stack)) -#define STACK_SIZE() (ctx->frame->stack_len) -#define BASIC_STACKADJ(n) (stack_pointer += n) -#ifdef Py_DEBUG - #define STACK_GROW(n) do { \ - assert(n >= 0); \ - BASIC_STACKADJ(n); \ - if (STACK_LEVEL() > STACK_SIZE()) { \ - DPRINTF(2, "err: %d, %d\n", STACK_SIZE(), STACK_LEVEL())\ - } \ - assert(STACK_LEVEL() <= STACK_SIZE()); \ - } while (0) - #define STACK_SHRINK(n) do { \ - assert(n >= 0); \ - assert(STACK_LEVEL() >= n); \ - BASIC_STACKADJ(-(n)); \ - } while (0) -#else - #define STACK_GROW(n) BASIC_STACKADJ(n) - #define STACK_SHRINK(n) BASIC_STACKADJ(-(n)) -#endif -#define PEEK(idx) (((stack_pointer)[-(idx)])) #define GETLOCAL(idx) ((ctx->frame->locals[idx])) -#define CURRENT_OPARG() (oparg) - -#define CURRENT_OPERAND() (operand) - -#define TIER_TWO_ONLY ((void)0) #define REPLACE_OP(op, arg, oper) \ new_inst.opcode = op; \ new_inst.oparg = arg; \ @@ -612,7 +591,6 @@ uop_abstract_interpret_single_inst( int oparg = inst->oparg; uint32_t opcode = inst->opcode; - uint64_t operand = inst->operand; _Py_UOpsSymType **stack_pointer = ctx->frame->stack_pointer; _PyUOpInstruction new_inst = *inst; @@ -637,9 +615,6 @@ uop_abstract_interpret_single_inst( return 0; -pop_2_error_tier_two: - STACK_SHRINK(1); - STACK_SHRINK(1); error: DPRINTF(1, "Encountered error in abstract interpreter\n"); return -1; @@ -885,6 +860,7 @@ uop_abstract_interpret( if (!(_PyUop_Flags[curr->opcode] & HAS_PURE_FLAG) && !op_is_bookkeeping(curr->opcode) && + !op_is_data_movement_only(curr->opcode) && !(_PyUop_Flags[curr->opcode] & HAS_PASSTHROUGH_FLAG)) { DPRINTF(3, "Impure %s\n", _PyOpcode_uop_name[curr->opcode]); if (needs_clear_locals) { diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index 69f6ff5c409659..b774b6d4767b95 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -95,7 +95,7 @@ dummy_func(void) { } op(_LOAD_CONST_INLINE, (ptr/4 -- value)) { - _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); + _Py_UOpsSymType *sym_const = sym_init_const(ctx, ptr); if (sym_const == NULL) { goto error; } @@ -104,7 +104,7 @@ dummy_func(void) { } op(_LOAD_CONST_INLINE_BORROW, (ptr/4 -- value)) { - _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); + _Py_UOpsSymType *sym_const = sym_init_const(ctx, ptr); if (sym_const == NULL) { goto error; } @@ -113,7 +113,7 @@ dummy_func(void) { } op(_LOAD_CONST_INLINE_WITH_NULL, (ptr/4 -- value, null)) { - _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); + _Py_UOpsSymType *sym_const = sym_init_const(ctx, ptr); if (sym_const == NULL) { goto error; } @@ -127,7 +127,7 @@ dummy_func(void) { } op(_LOAD_CONST_INLINE_BORROW_WITH_NULL, (ptr/4 -- value, null)) { - _Py_UOpsSymType *sym_const = sym_init_const(ctx, (PyObject *)inst->operand); + _Py_UOpsSymType *sym_const = sym_init_const(ctx, ptr); if (sym_const == NULL) { goto error; } @@ -200,8 +200,20 @@ dummy_func(void) { stack_pointer = new_frame->stack_pointer; } + op(_UNPACK_SEQUENCE, (seq -- values[oparg])) { + /* This has to be done manually */ + (void)seq; + for (int i = 0; i < oparg; i++) { + values[i] = sym_init_unknown(ctx); + if (values[i] == NULL) { + goto error; + } + } + } + op(_UNPACK_EX, (seq -- values[oparg & 0xFF], unused, unused[oparg >> 8])) { /* This has to be done manually */ + (void)seq; int totalargs = (oparg & 0xFF) + (oparg >> 8) + 1; for (int i = 0; i < totalargs; i++) { values[i] = sym_init_unknown(ctx); diff --git a/Tools/cases_generator/stack.py b/Tools/cases_generator/stack.py index 28ad9507b8e0bb..97a301142d59c7 100644 --- a/Tools/cases_generator/stack.py +++ b/Tools/cases_generator/stack.py @@ -3,7 +3,7 @@ from dataclasses import dataclass from cwriter import CWriter -UNUSED = {"unused", "__unused_"} +UNUSED = {"unused"} def maybe_parenthesize(sym: str) -> str: diff --git a/Tools/cases_generator/tier2_abstract_generator.py b/Tools/cases_generator/tier2_abstract_generator.py index c04924e179932e..fba814b20e8fda 100644 --- a/Tools/cases_generator/tier2_abstract_generator.py +++ b/Tools/cases_generator/tier2_abstract_generator.py @@ -28,15 +28,17 @@ from cwriter import CWriter from typing import TextIO, Iterator from lexer import Token -from stack import StackOffset, Stack, SizeMismatch +from stack import StackOffset, Stack, SizeMismatch, UNUSED DEFAULT_OUTPUT = ROOT / "Python/abstract_interp_cases.c.h" DEFAULT_ABSTRACT_INUPT = ROOT / "Python/tier2_redundancy_eliminator_bytecodes.c" + def validate_uop(override: Uop, uop: Uop) -> None: # To do pass + def type_name(var: StackItem) -> str: if var.is_array(): return f"_Py_UOpsSymType **" @@ -45,20 +47,20 @@ def type_name(var: StackItem) -> str: return f"_Py_UOpsSymType *" -def declare_variables(uop: Uop, out: CWriter, peeks: bool) -> None: +def declare_variables(uop: Uop, out: CWriter, skip_inputs) -> None: variables = {"unused"} - for var in reversed(uop.stack.inputs): - if var.peek and not peeks: - continue - if var.name not in variables: - variables.add(var.name) - if var.condition: - out.emit(f"{type_name(var)}{var.name} = sym_init_null(ctx);\n") - out.emit(f"if({var.name}) {{goto error;}}\n") - else: - out.emit(f"{type_name(var)}{var.name};\n") + if not skip_inputs: + for var in reversed(uop.stack.inputs): + if var.name not in variables: + variables.add(var.name) + if var.condition: + out.emit(f"{type_name(var)}{var.name} = sym_init_null(ctx);\n") + out.emit(f"if({var.name}) {{goto error;}}\n") + else: + out.emit(f"{type_name(var)}{var.name};\n") + has_type_prop = any(output.type_prop is not None for output in uop.stack.outputs) for var in uop.stack.outputs: - if var.peek and not peeks: + if var.peek and not has_type_prop: continue if var.name not in variables: variables.add(var.name) @@ -68,19 +70,21 @@ def declare_variables(uop: Uop, out: CWriter, peeks: bool) -> None: else: out.emit(f"{type_name(var)}{var.name};\n") + def decref_inputs( - out: CWriter, - tkn: Token, - tkn_iter: Iterator[Token], - uop: Uop, - stack: Stack, - inst: Instruction | None, + out: CWriter, + tkn: Token, + tkn_iter: Iterator[Token], + uop: Uop, + stack: Stack, + inst: Instruction | None, ) -> None: next(tkn_iter) next(tkn_iter) next(tkn_iter) out.emit_at("", tkn) + def emit_default(out: CWriter, uop: Uop) -> None: for i, var in enumerate(uop.stack.outputs): if var.name != "unused" and not var.peek: @@ -96,25 +100,33 @@ def emit_default(out: CWriter, uop: Uop) -> None: out.emit(f"{var.name} = sym_init_unknown(ctx);\n") out.emit(f"if ({var.name} == NULL) goto error;\n") + def write_uop( - override: Uop | None, uop: Uop, out: CWriter, stack: Stack, debug: bool + override: Uop | None, + uop: Uop, + out: CWriter, + stack: Stack, + debug: bool, + skip_inputs: bool, ) -> None: try: + has_type_prop = any( + output.type_prop is not None for output in (override or uop).stack.outputs + ) prototype = override if override else uop - has_type_prop = any(output.type_prop is not None for output in uop.stack.outputs) - peeks = override is not None or has_type_prop + is_override = override is not None out.start_line() for var in reversed(prototype.stack.inputs): - if not var.peek or peeks: + if not skip_inputs or (has_type_prop and var.peek): out.emit(stack.pop(var)) if not prototype.properties.stores_sp: for i, var in enumerate(prototype.stack.outputs): - if not var.peek or peeks: + if not var.peek or is_override or has_type_prop: out.emit(stack.push(var)) if debug: args = [] for var in prototype.stack.inputs: - if not var.peek or peeks: + if not var.peek or is_override: args.append(var.name) out.emit(f'DEBUG_PRINTF({", ".join(args)});\n') if override or has_type_prop: @@ -129,24 +141,29 @@ def write_uop( if override: replacement_funcs = { "DECREF_INPUTS": decref_inputs, - "SYNC_SP": replace_sync_sp + "SYNC_SP": replace_sync_sp, } emit_tokens(out, override, stack, None, replacement_funcs) else: emit_default(out, uop) # Type propagation - for output in uop.stack.outputs: - if (typ := output.type_prop): + out.emit("\n") + for output in (override or uop).stack.outputs: + if typ := output.type_prop: typname, refinement = typ refinement = refinement or "0" out.emit(f"sym_set_type({output.name}, {typname}, {refinement});\n") + else: + # Silence compiler unused variable warnings. + if has_type_prop and output.name not in UNUSED: + out.emit(f"(void){output.name};\n") if prototype.properties.stores_sp: for i, var in enumerate(prototype.stack.outputs): - if not var.peek or peeks: + if not var.peek or is_override: out.emit(stack.push(var)) out.start_line() - stack.flush(out) + stack.flush(out, cast_type="_Py_UOpsSymType *") except SizeMismatch as ex: raise analysis_error(ex.args[0], uop.body[0]) @@ -155,7 +172,11 @@ def write_uop( def generate_abstract_interpreter( - filenames: list[str], abstract: Analysis, base: Analysis, outfile: TextIO, debug: bool + filenames: list[str], + abstract: Analysis, + base: Analysis, + outfile: TextIO, + debug: bool, ) -> None: write_header(__file__, filenames, outfile) out = CWriter(outfile, 2, False) @@ -174,12 +195,11 @@ def generate_abstract_interpreter( continue out.emit(f"case {uop.name}: {{\n") if override: - declare_variables(override, out, True) + declare_variables(override or uop, out, skip_inputs=False) else: - has_type_prop = any(output.type_prop is not None for output in uop.stack.outputs) - declare_variables(uop, out, has_type_prop) + declare_variables(override or uop, out, skip_inputs=True) stack = Stack() - write_uop(override, uop, out, stack, debug) + write_uop(override, uop, out, stack, debug, skip_inputs=(override is None)) out.start_line() out.emit("break;\n") out.emit("}") @@ -196,17 +216,13 @@ def generate_abstract_interpreter( ) -arg_parser.add_argument( - "input", nargs=1, help="Abstract interpreter definition file" -) +arg_parser.add_argument("input", nargs=1, help="Abstract interpreter definition file") arg_parser.add_argument( "base", nargs=argparse.REMAINDER, help="The base instruction definition file(s)" ) -arg_parser.add_argument( - "-d", "--debug", help="Insert debug calls", action="store_true" -) +arg_parser.add_argument("-d", "--debug", help="Insert debug calls", action="store_true") if __name__ == "__main__": args = arg_parser.parse_args() @@ -216,4 +232,4 @@ def generate_abstract_interpreter( abstract = analyze_files(args.input) base = analyze_files(args.base) with open(args.output, "w") as outfile: - generate_abstract_interpreter(args.input, abstract, base, outfile, args.debug) \ No newline at end of file + generate_abstract_interpreter(args.input, abstract, base, outfile, args.debug) From 66bfce59802f913cbf65781a79cc57b0c6e9c7de Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 6 Feb 2024 22:57:06 +0800 Subject: [PATCH 06/52] fix mypy issues --- Python/optimizer_analysis.c | 2 +- Tools/cases_generator/tier2_abstract_generator.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 94da4f34da694f..7b9dcd1832a5cc 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -583,7 +583,7 @@ uop_abstract_interpret_single_inst( #define GETLOCAL(idx) ((ctx->frame->locals[idx])) -#define REPLACE_OP(op, arg, oper) \ +#define REPLACE_OP(op, arg, oper) \ new_inst.opcode = op; \ new_inst.oparg = arg; \ new_inst.operand = oper; diff --git a/Tools/cases_generator/tier2_abstract_generator.py b/Tools/cases_generator/tier2_abstract_generator.py index fba814b20e8fda..ca73700ed9ce18 100644 --- a/Tools/cases_generator/tier2_abstract_generator.py +++ b/Tools/cases_generator/tier2_abstract_generator.py @@ -47,7 +47,7 @@ def type_name(var: StackItem) -> str: return f"_Py_UOpsSymType *" -def declare_variables(uop: Uop, out: CWriter, skip_inputs) -> None: +def declare_variables(uop: Uop, out: CWriter, skip_inputs: bool) -> None: variables = {"unused"} if not skip_inputs: for var in reversed(uop.stack.inputs): @@ -195,9 +195,9 @@ def generate_abstract_interpreter( continue out.emit(f"case {uop.name}: {{\n") if override: - declare_variables(override or uop, out, skip_inputs=False) + declare_variables(override, out, skip_inputs=False) else: - declare_variables(override or uop, out, skip_inputs=True) + declare_variables(uop, out, skip_inputs=True) stack = Stack() write_uop(override, uop, out, stack, debug, skip_inputs=(override is None)) out.start_line() From 3789cd9e66a1edddc3033269df0c70773597ef87 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 6 Feb 2024 23:19:35 +0800 Subject: [PATCH 07/52] fix tests and address review --- Tools/c-analyzer/cpython/_parser.py | 1 + Tools/cases_generator/README.md | 3 +++ Tools/cases_generator/tier2_abstract_generator.py | 6 +++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index dffb0c46984c50..527c09ea25a1d1 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -87,6 +87,7 @@ def clean_lines(text): # not actually source Python/bytecodes.c +Python/tier2_redundancy_eliminator_bytecodes.c # mimalloc Objects/mimalloc/*.c diff --git a/Tools/cases_generator/README.md b/Tools/cases_generator/README.md index 7fec8a882336cd..350779b571a0c7 100644 --- a/Tools/cases_generator/README.md +++ b/Tools/cases_generator/README.md @@ -13,6 +13,9 @@ What's currently here: - `parser.py` helper for interactions with `parsing.py` - `tierN_generator.py`: a couple of driver scripts to read `Python/bytecodes.c` and write `Python/generated_cases.c.h` (and several other files) +- `tier2_abstract_generator.py`: reads `Python/bytecodes.c` and + `Python/tier2_redundancy_eliminator_bytecodes.c` and writes + `Python/abstract_interp_cases.c.h` - `stack.py`: code to handle generalized stack effects - `cwriter.py`: code which understands tokens and how to format C code; main class: `CWriter` diff --git a/Tools/cases_generator/tier2_abstract_generator.py b/Tools/cases_generator/tier2_abstract_generator.py index ca73700ed9ce18..b08eb0157226be 100644 --- a/Tools/cases_generator/tier2_abstract_generator.py +++ b/Tools/cases_generator/tier2_abstract_generator.py @@ -1,6 +1,6 @@ """Generate the cases for the tier 2 redundancy eliminator/abstract interpreter. Reads the instruction definitions from bytecodes.c. and tier2_redundancy_eliminator.bytecodes.c -Writes the cases to tier2_abstract_cases.c.h, which is #included in ceval.c. +Writes the cases to abstract_interp_cases.c.h, which is #included in Python/optimizer_analysis.c. """ import argparse @@ -31,7 +31,7 @@ from stack import StackOffset, Stack, SizeMismatch, UNUSED DEFAULT_OUTPUT = ROOT / "Python/abstract_interp_cases.c.h" -DEFAULT_ABSTRACT_INUPT = ROOT / "Python/tier2_redundancy_eliminator_bytecodes.c" +DEFAULT_ABSTRACT_INPUT = ROOT / "Python/tier2_redundancy_eliminator_bytecodes.c" def validate_uop(override: Uop, uop: Uop) -> None: @@ -228,7 +228,7 @@ def generate_abstract_interpreter( args = arg_parser.parse_args() if len(args.base) == 0: args.input.append(DEFAULT_INPUT) - args.input.append(DEFAULT_ABSTRACT_INUPT) + args.input.append(DEFAULT_ABSTRACT_INPUT) abstract = analyze_files(args.input) base = analyze_files(args.base) with open(args.output, "w") as outfile: From 20d087bbcd5691988b48c11551f48f75d042dcd2 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 7 Feb 2024 00:12:12 +0800 Subject: [PATCH 08/52] add tests for abstract cases generator --- Lib/test/test_generated_cases.py | 165 ++++++++++++++++++ Python/abstract_interp_cases.c.h | 160 ----------------- .../tier2_abstract_generator.py | 13 +- 3 files changed, 177 insertions(+), 161 deletions(-) diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index ca1228ee7008a9..8c207263c9cab9 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -33,6 +33,7 @@ def skip_if_different_mount_drives(): import parser from stack import Stack import tier1_generator + import tier2_abstract_generator def handle_stderr(): @@ -793,5 +794,169 @@ def test_annotated_op(self): self.run_cases_test(input, output) +class TestGeneratedAbstractCases(unittest.TestCase): + def setUp(self) -> None: + super().setUp() + self.maxDiff = None + + self.temp_dir = tempfile.gettempdir() + self.temp_input_filename = os.path.join(self.temp_dir, "input.txt") + self.temp_input2_filename = os.path.join(self.temp_dir, "input2.txt") + self.temp_output_filename = os.path.join(self.temp_dir, "output.txt") + + def tearDown(self) -> None: + for filename in [ + self.temp_input_filename, + self.temp_input2_filename, + self.temp_output_filename, + ]: + try: + os.remove(filename) + except: + pass + super().tearDown() + + def run_cases_test(self, input: str, input2: str, expected: str): + with open(self.temp_input_filename, "w+") as temp_input: + temp_input.write(parser.BEGIN_MARKER) + temp_input.write(input) + temp_input.write(parser.END_MARKER) + temp_input.flush() + + with open(self.temp_input2_filename, "w+") as temp_input: + temp_input.write(parser.BEGIN_MARKER) + temp_input.write(input2) + temp_input.write(parser.END_MARKER) + temp_input.flush() + + with handle_stderr(): + tier2_abstract_generator.generate_tier2_abstract_from_files( + [self.temp_input_filename, self.temp_input2_filename], + self.temp_output_filename + ) + + with open(self.temp_output_filename) as temp_output: + lines = temp_output.readlines() + while lines and lines[0].startswith(("// ", "#", " #", "\n")): + lines.pop(0) + while lines and lines[-1].startswith(("#", "\n")): + lines.pop(-1) + actual = "".join(lines) + self.assertEqual(actual.strip(), expected.strip()) + + def test_overridden_abstract(self): + input = """ + pure op(OP, (--)) { + spam(); + } + """ + input2 = """ + pure op(OP, (--)) { + eggs(); + } + """ + output = """ + case OP: { + eggs(); + break; + } + """ + self.run_cases_test(input, input2, output) + + def test_overridden_abstract_args(self): + input = """ + pure op(OP, (arg1 -- out)) { + spam(); + } + """ + input2 = """ + op(OP, (arg1 -- out)) { + eggs(); + } + """ + output = """ + case OP: { + _Py_UOpsSymType *arg1; + _Py_UOpsSymType *out; + arg1 = stack_pointer[-1]; + eggs(); + stack_pointer[-1] = out; + break; + } + """ + self.run_cases_test(input, input2, output) + + def test_no_overridden_case(self): + input = """ + pure op(OP, (arg1 -- out)) { + spam(); + } + """ + input2 = """ + pure op(OTHER, (arg1 -- out)) { + spam(); + } + """ + output = """ + case OP: { + _Py_UOpsSymType *out; + out = sym_init_unknown(ctx); + if (out == NULL) goto error; + stack_pointer[0] = out; + stack_pointer += 1; + break; + } + """ + self.run_cases_test(input, input2, output) + + def test_no_overridden_case_type_prop(self): + input = """ + pure op(OP, (arg1 -- out: &PYLONG_TYPE)) { + spam(); + } + """ + input2 = """ + pure op(OTHER, (arg1 -- out)) { + spam(); + } + """ + output = """ + case OP: { + _Py_UOpsSymType *out; + out = sym_init_unknown(ctx); + if (out == NULL) goto error; + + sym_set_type(out, PYLONG_TYPE, 0); + stack_pointer[0] = out; + stack_pointer += 1; + break; + } + """ + self.run_cases_test(input, input2, output) + + def test_overridden_case_type_prop(self): + input = """ + pure op(OP, (arg1 -- out: &PYLONG_TYPE)) { + spam(); + } + """ + input2 = """ + pure op(OP, (arg1 -- out: &PYFLOAT_TYPE)) { + spam(); + } + """ + output = """ + case OP: { + _Py_UOpsSymType *arg1; + _Py_UOpsSymType *out; + arg1 = stack_pointer[-1]; + spam(); + sym_set_type(out, PYFLOAT_TYPE, 0); + stack_pointer[-1] = out; + break; + } + """ + self.run_cases_test(input, input2, output) + if __name__ == "__main__": unittest.main() diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index 849cf2e1a8cd03..0cb21531c00216 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -4,12 +4,10 @@ // Do not edit! case _NOP: { - break; } case _RESUME_CHECK: { - break; } @@ -65,7 +63,6 @@ } case _POP_TOP: { - break; } @@ -84,7 +81,6 @@ _Py_UOpsSymType *value; value = sym_init_unknown(ctx); if (value == NULL) goto error; - stack_pointer[0] = value; stack_pointer += 1; break; @@ -94,7 +90,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -104,7 +99,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -114,14 +108,12 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; } case _TO_BOOL_BOOL: { - break; } @@ -129,7 +121,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -139,7 +130,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -149,7 +139,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -159,7 +148,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -169,7 +157,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -179,7 +166,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -203,7 +189,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -232,7 +217,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -311,7 +295,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -321,14 +304,12 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; } case _STORE_SLICE: { - break; } @@ -336,7 +317,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -346,7 +326,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -356,7 +335,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -366,7 +344,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -375,32 +352,26 @@ /* _BINARY_SUBSCR_GETITEM is not a viable micro-op for tier 2 */ case _LIST_APPEND: { - break; } case _SET_ADD: { - break; } case _STORE_SUBSCR: { - break; } case _STORE_SUBSCR_LIST_INT: { - break; } case _STORE_SUBSCR_DICT: { - break; } case _DELETE_SUBSCR: { - break; } @@ -408,7 +379,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -418,7 +388,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -446,7 +415,6 @@ _Py_UOpsSymType *iter; iter = sym_init_unknown(ctx); if (iter == NULL) goto error; - stack_pointer[0] = iter; stack_pointer += 1; break; @@ -456,7 +424,6 @@ _Py_UOpsSymType *awaitable; awaitable = sym_init_unknown(ctx); if (awaitable == NULL) goto error; - stack_pointer[0] = awaitable; stack_pointer += 1; break; @@ -466,7 +433,6 @@ _Py_UOpsSymType *iter; iter = sym_init_unknown(ctx); if (iter == NULL) goto error; - stack_pointer[0] = iter; stack_pointer += 1; break; @@ -479,7 +445,6 @@ /* _INSTRUMENTED_YIELD_VALUE is not a viable micro-op for tier 2 */ case _POP_EXCEPT: { - break; } @@ -487,7 +452,6 @@ _Py_UOpsSymType *value; value = sym_init_unknown(ctx); if (value == NULL) goto error; - stack_pointer[0] = value; stack_pointer += 1; break; @@ -497,19 +461,16 @@ _Py_UOpsSymType *bc; bc = sym_init_unknown(ctx); if (bc == NULL) goto error; - stack_pointer[0] = bc; stack_pointer += 1; break; } case _STORE_NAME: { - break; } case _DELETE_NAME: { - break; } @@ -537,7 +498,6 @@ values[_i] = sym_init_unknown(ctx); if (values[_i] == NULL) goto error; } - stack_pointer += oparg; break; } @@ -549,7 +509,6 @@ values[_i] = sym_init_unknown(ctx); if (values[_i] == NULL) goto error; } - stack_pointer += oparg; break; } @@ -561,7 +520,6 @@ values[_i] = sym_init_unknown(ctx); if (values[_i] == NULL) goto error; } - stack_pointer += oparg; break; } @@ -585,22 +543,18 @@ } case _STORE_ATTR: { - break; } case _DELETE_ATTR: { - break; } case _STORE_GLOBAL: { - break; } case _DELETE_GLOBAL: { - break; } @@ -608,7 +562,6 @@ _Py_UOpsSymType *locals; locals = sym_init_unknown(ctx); if (locals == NULL) goto error; - stack_pointer[0] = locals; stack_pointer += 1; break; @@ -618,7 +571,6 @@ _Py_UOpsSymType *v; v = sym_init_unknown(ctx); if (v == NULL) goto error; - stack_pointer[0] = v; stack_pointer += 1; break; @@ -628,7 +580,6 @@ _Py_UOpsSymType *v; v = sym_init_unknown(ctx); if (v == NULL) goto error; - stack_pointer[0] = v; stack_pointer += 1; break; @@ -642,7 +593,6 @@ if (res == NULL) goto error; null = sym_init_unknown(ctx); if (null == NULL) goto error; - stack_pointer[0] = res; if (oparg & 1) stack_pointer[1] = null; stack_pointer += 1 + (oparg & 1); @@ -650,12 +600,10 @@ } case _GUARD_GLOBALS_VERSION: { - break; } case _GUARD_BUILTINS_VERSION: { - break; } @@ -667,7 +615,6 @@ if (res == NULL) goto error; null = sym_init_unknown(ctx); if (null == NULL) goto error; - stack_pointer[0] = res; if (oparg & 1) stack_pointer[1] = null; stack_pointer += 1 + (oparg & 1); @@ -682,7 +629,6 @@ if (res == NULL) goto error; null = sym_init_unknown(ctx); if (null == NULL) goto error; - stack_pointer[0] = res; if (oparg & 1) stack_pointer[1] = null; stack_pointer += 1 + (oparg & 1); @@ -690,17 +636,14 @@ } case _DELETE_FAST: { - break; } case _MAKE_CELL: { - break; } case _DELETE_DEREF: { - break; } @@ -708,7 +651,6 @@ _Py_UOpsSymType *value; value = sym_init_unknown(ctx); if (value == NULL) goto error; - stack_pointer[0] = value; stack_pointer += 1; break; @@ -718,19 +660,16 @@ _Py_UOpsSymType *value; value = sym_init_unknown(ctx); if (value == NULL) goto error; - stack_pointer[0] = value; stack_pointer += 1; break; } case _STORE_DEREF: { - break; } case _COPY_FREE_VARS: { - break; } @@ -738,7 +677,6 @@ _Py_UOpsSymType *str; str = sym_init_unknown(ctx); if (str == NULL) goto error; - stack_pointer[0] = str; stack_pointer += 1; break; @@ -748,7 +686,6 @@ _Py_UOpsSymType *tup; tup = sym_init_unknown(ctx); if (tup == NULL) goto error; - stack_pointer[0] = tup; stack_pointer += 1; break; @@ -758,19 +695,16 @@ _Py_UOpsSymType *list; list = sym_init_unknown(ctx); if (list == NULL) goto error; - stack_pointer[0] = list; stack_pointer += 1; break; } case _LIST_EXTEND: { - break; } case _SET_UPDATE: { - break; } @@ -778,7 +712,6 @@ _Py_UOpsSymType *set; set = sym_init_unknown(ctx); if (set == NULL) goto error; - stack_pointer[0] = set; stack_pointer += 1; break; @@ -788,14 +721,12 @@ _Py_UOpsSymType *map; map = sym_init_unknown(ctx); if (map == NULL) goto error; - stack_pointer[0] = map; stack_pointer += 1; break; } case _SETUP_ANNOTATIONS: { - break; } @@ -803,24 +734,20 @@ _Py_UOpsSymType *map; map = sym_init_unknown(ctx); if (map == NULL) goto error; - stack_pointer[0] = map; stack_pointer += 1; break; } case _DICT_UPDATE: { - break; } case _DICT_MERGE: { - break; } case _MAP_ADD: { - break; } @@ -830,7 +757,6 @@ _Py_UOpsSymType *attr; attr = sym_init_unknown(ctx); if (attr == NULL) goto error; - stack_pointer[0] = attr; stack_pointer += 1 + ((0) ? 1 : 0); break; @@ -843,7 +769,6 @@ if (attr == NULL) goto error; self_or_null = sym_init_unknown(ctx); if (self_or_null == NULL) goto error; - stack_pointer[0] = attr; stack_pointer[1] = self_or_null; stack_pointer += 2; @@ -877,7 +802,6 @@ } case _CHECK_MANAGED_OBJECT_HAS_VALUES: { - break; } @@ -889,7 +813,6 @@ if (attr == NULL) goto error; null = sym_init_unknown(ctx); if (null == NULL) goto error; - stack_pointer[0] = attr; if (oparg & 1) stack_pointer[1] = null; stack_pointer += 1 + (oparg & 1); @@ -897,7 +820,6 @@ } case _CHECK_ATTR_MODULE: { - break; } @@ -909,7 +831,6 @@ if (attr == NULL) goto error; null = sym_init_unknown(ctx); if (null == NULL) goto error; - stack_pointer[0] = attr; if (oparg & 1) stack_pointer[1] = null; stack_pointer += 1 + (oparg & 1); @@ -917,7 +838,6 @@ } case _CHECK_ATTR_WITH_HINT: { - break; } @@ -929,7 +849,6 @@ if (attr == NULL) goto error; null = sym_init_unknown(ctx); if (null == NULL) goto error; - stack_pointer[0] = attr; if (oparg & 1) stack_pointer[1] = null; stack_pointer += 1 + (oparg & 1); @@ -944,7 +863,6 @@ if (attr == NULL) goto error; null = sym_init_unknown(ctx); if (null == NULL) goto error; - stack_pointer[0] = attr; if (oparg & 1) stack_pointer[1] = null; stack_pointer += 1 + (oparg & 1); @@ -952,7 +870,6 @@ } case _CHECK_ATTR_CLASS: { - break; } @@ -964,7 +881,6 @@ if (attr == NULL) goto error; null = sym_init_unknown(ctx); if (null == NULL) goto error; - stack_pointer[0] = attr; if (oparg & 1) stack_pointer[1] = null; stack_pointer += 1 + (oparg & 1); @@ -984,14 +900,12 @@ } case _STORE_ATTR_INSTANCE_VALUE: { - break; } /* _STORE_ATTR_WITH_HINT is not a viable micro-op for tier 2 */ case _STORE_ATTR_SLOT: { - break; } @@ -999,7 +913,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1009,7 +922,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1019,7 +931,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1029,7 +940,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1039,7 +949,6 @@ _Py_UOpsSymType *b; b = sym_init_unknown(ctx); if (b == NULL) goto error; - stack_pointer[0] = b; stack_pointer += 1; break; @@ -1049,7 +958,6 @@ _Py_UOpsSymType *b; b = sym_init_unknown(ctx); if (b == NULL) goto error; - stack_pointer[0] = b; stack_pointer += 1; break; @@ -1062,7 +970,6 @@ if (rest == NULL) goto error; match = sym_init_unknown(ctx); if (match == NULL) goto error; - stack_pointer[0] = rest; stack_pointer[1] = match; stack_pointer += 2; @@ -1073,7 +980,6 @@ _Py_UOpsSymType *b; b = sym_init_unknown(ctx); if (b == NULL) goto error; - stack_pointer[0] = b; stack_pointer += 1; break; @@ -1089,7 +995,6 @@ _Py_UOpsSymType *b; b = sym_init_unknown(ctx); if (b == NULL) goto error; - stack_pointer[0] = b; stack_pointer += 1; break; @@ -1099,7 +1004,6 @@ _Py_UOpsSymType *len_o; len_o = sym_init_unknown(ctx); if (len_o == NULL) goto error; - stack_pointer[0] = len_o; stack_pointer += 1; break; @@ -1109,7 +1013,6 @@ _Py_UOpsSymType *attrs; attrs = sym_init_unknown(ctx); if (attrs == NULL) goto error; - stack_pointer[0] = attrs; stack_pointer += 1; break; @@ -1119,7 +1022,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1129,7 +1031,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1139,7 +1040,6 @@ _Py_UOpsSymType *values_or_none; values_or_none = sym_init_unknown(ctx); if (values_or_none == NULL) goto error; - stack_pointer[0] = values_or_none; stack_pointer += 1; break; @@ -1149,7 +1049,6 @@ _Py_UOpsSymType *iter; iter = sym_init_unknown(ctx); if (iter == NULL) goto error; - stack_pointer[0] = iter; stack_pointer += 1; break; @@ -1159,7 +1058,6 @@ _Py_UOpsSymType *iter; iter = sym_init_unknown(ctx); if (iter == NULL) goto error; - stack_pointer[0] = iter; stack_pointer += 1; break; @@ -1171,7 +1069,6 @@ _Py_UOpsSymType *next; next = sym_init_unknown(ctx); if (next == NULL) goto error; - stack_pointer[0] = next; stack_pointer += 1; break; @@ -1180,14 +1077,12 @@ /* _INSTRUMENTED_FOR_ITER is not a viable micro-op for tier 2 */ case _ITER_CHECK_LIST: { - break; } /* _ITER_JUMP_LIST is not a viable micro-op for tier 2 */ case _GUARD_NOT_EXHAUSTED_LIST: { - break; } @@ -1195,21 +1090,18 @@ _Py_UOpsSymType *next; next = sym_init_unknown(ctx); if (next == NULL) goto error; - stack_pointer[0] = next; stack_pointer += 1; break; } case _ITER_CHECK_TUPLE: { - break; } /* _ITER_JUMP_TUPLE is not a viable micro-op for tier 2 */ case _GUARD_NOT_EXHAUSTED_TUPLE: { - break; } @@ -1217,21 +1109,18 @@ _Py_UOpsSymType *next; next = sym_init_unknown(ctx); if (next == NULL) goto error; - stack_pointer[0] = next; stack_pointer += 1; break; } case _ITER_CHECK_RANGE: { - break; } /* _ITER_JUMP_RANGE is not a viable micro-op for tier 2 */ case _GUARD_NOT_EXHAUSTED_RANGE: { - break; } @@ -1258,7 +1147,6 @@ if (exit == NULL) goto error; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = exit; stack_pointer[1] = res; stack_pointer += 2; @@ -1272,7 +1160,6 @@ if (exit == NULL) goto error; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = exit; stack_pointer[1] = res; stack_pointer += 2; @@ -1283,7 +1170,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1296,7 +1182,6 @@ if (prev_exc == NULL) goto error; new_exc = sym_init_unknown(ctx); if (new_exc == NULL) goto error; - stack_pointer[0] = prev_exc; stack_pointer[1] = new_exc; stack_pointer += 2; @@ -1304,7 +1189,6 @@ } case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT: { - break; } @@ -1325,7 +1209,6 @@ if (attr == NULL) goto error; self = sym_init_unknown(ctx); if (self == NULL) goto error; - stack_pointer[0] = attr; if (1) stack_pointer[1] = self; stack_pointer += 1 + ((1) ? 1 : 0); @@ -1340,7 +1223,6 @@ if (attr == NULL) goto error; self = sym_init_unknown(ctx); if (self == NULL) goto error; - stack_pointer[0] = attr; if (1) stack_pointer[1] = self; stack_pointer += 1 + ((1) ? 1 : 0); @@ -1351,7 +1233,6 @@ _Py_UOpsSymType *attr; attr = sym_init_unknown(ctx); if (attr == NULL) goto error; - stack_pointer[0] = attr; stack_pointer += 1 + ((0) ? 1 : 0); break; @@ -1361,14 +1242,12 @@ _Py_UOpsSymType *attr; attr = sym_init_unknown(ctx); if (attr == NULL) goto error; - stack_pointer[0] = attr; stack_pointer += 1 + ((0) ? 1 : 0); break; } case _CHECK_ATTR_METHOD_LAZY_DICT: { - break; } @@ -1380,7 +1259,6 @@ if (attr == NULL) goto error; self = sym_init_unknown(ctx); if (self == NULL) goto error; - stack_pointer[0] = attr; if (1) stack_pointer[1] = self; stack_pointer += 1 + ((1) ? 1 : 0); @@ -1409,7 +1287,6 @@ if (func == NULL) goto error; self = sym_init_unknown(ctx); if (self == NULL) goto error; - stack_pointer[0] = func; stack_pointer[1] = self; stack_pointer += 2; @@ -1438,7 +1315,6 @@ } case _CHECK_STACK_SPACE: { - break; } @@ -1501,7 +1377,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1511,7 +1386,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1521,7 +1395,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1530,7 +1403,6 @@ /* _CALL_ALLOC_AND_ENTER_INIT is not a viable micro-op for tier 2 */ case _EXIT_INIT_CHECK: { - break; } @@ -1538,7 +1410,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1548,7 +1419,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1558,7 +1428,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1568,7 +1437,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1578,7 +1446,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1588,7 +1455,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1598,7 +1464,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1608,7 +1473,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1618,7 +1482,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1628,7 +1491,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1646,7 +1508,6 @@ _Py_UOpsSymType *func; func = sym_init_unknown(ctx); if (func == NULL) goto error; - stack_pointer[0] = func; stack_pointer += 1; break; @@ -1656,7 +1517,6 @@ _Py_UOpsSymType *func; func = sym_init_unknown(ctx); if (func == NULL) goto error; - stack_pointer[0] = func; stack_pointer += 1; break; @@ -1666,7 +1526,6 @@ _Py_UOpsSymType *slice; slice = sym_init_unknown(ctx); if (slice == NULL) goto error; - stack_pointer[0] = slice; stack_pointer += 1; break; @@ -1676,7 +1535,6 @@ _Py_UOpsSymType *result; result = sym_init_unknown(ctx); if (result == NULL) goto error; - stack_pointer[0] = result; stack_pointer += 1; break; @@ -1686,7 +1544,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1696,7 +1553,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1717,7 +1573,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; stack_pointer += 1; break; @@ -1728,7 +1583,6 @@ _Py_UOpsSymType *bottom; top = stack_pointer[-1]; bottom = stack_pointer[-2 - (oparg-2)]; - stack_pointer[-2 - (oparg-2)] = top; stack_pointer[-1] = bottom; break; @@ -1749,57 +1603,46 @@ /* _INSTRUMENTED_POP_JUMP_IF_NOT_NONE is not a viable micro-op for tier 2 */ case _GUARD_IS_TRUE_POP: { - break; } case _GUARD_IS_FALSE_POP: { - break; } case _GUARD_IS_NONE_POP: { - break; } case _GUARD_IS_NOT_NONE_POP: { - break; } case _JUMP_TO_TOP: { - break; } case _SET_IP: { - break; } case _SAVE_RETURN_OFFSET: { - break; } case _EXIT_TRACE: { - break; } case _JUMP_ABSOLUTE: { - break; } case _JUMP_ABSOLUTE_HEADER: { - break; } case _CHECK_VALIDITY: { - break; } @@ -1874,17 +1717,14 @@ } case _CHECK_GLOBALS: { - break; } case _CHECK_BUILTINS: { - break; } case _INTERNAL_INCREMENT_OPT_COUNTER: { - break; } diff --git a/Tools/cases_generator/tier2_abstract_generator.py b/Tools/cases_generator/tier2_abstract_generator.py index b08eb0157226be..0eb4aaefdebc74 100644 --- a/Tools/cases_generator/tier2_abstract_generator.py +++ b/Tools/cases_generator/tier2_abstract_generator.py @@ -147,7 +147,8 @@ def write_uop( else: emit_default(out, uop) # Type propagation - out.emit("\n") + if has_type_prop: + out.emit("\n") for output in (override or uop).stack.outputs: if typ := output.type_prop: typname, refinement = typ @@ -206,6 +207,16 @@ def generate_abstract_interpreter( out.emit("\n\n") +def generate_tier2_abstract_from_files( + filenames: list[str], outfilename: str, debug: bool=False +) -> None: + assert len(filenames) == 2, "Need a base file and an abstract cases file." + base = analyze_files([filenames[0]]) + abstract = analyze_files([filenames[1]]) + with open(outfilename, "w") as outfile: + generate_abstract_interpreter(filenames, abstract, base, outfile, debug) + + arg_parser = argparse.ArgumentParser( description="Generate the code for the tier 2 interpreter.", formatter_class=argparse.ArgumentDefaultsHelpFormatter, From 0f5852697bb0a78ad074a7d8f352c0240d227c7d Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 7 Feb 2024 00:31:00 +0800 Subject: [PATCH 09/52] patchcheck --- Lib/test/test_generated_cases.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index 8c207263c9cab9..a294c064ae6fdd 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -882,7 +882,7 @@ def test_overridden_abstract_args(self): eggs(); stack_pointer[-1] = out; break; - } + } """ self.run_cases_test(input, input2, output) From c55ba14261b43ce4fd4a2603e45a69029e3fab3f Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 7 Feb 2024 15:36:16 +0800 Subject: [PATCH 10/52] Address review --- Include/internal/pycore_uop_ids.h | 20 +- Include/internal/pycore_uop_metadata.h | 4 - Lib/test/test_capi/test_opt.py | 26 +-- Python/abstract_interp_cases.c.h | 51 ++--- Python/bytecodes.c | 24 +- Python/executor_cases.c.h | 11 - Python/jit.c | 18 +- Python/optimizer.c | 18 +- Python/optimizer_analysis.c | 206 +++++++++--------- .../tier2_redundancy_eliminator_bytecodes.c | 22 +- .../cases_generator/interpreter_definition.md | 2 +- .../tier2_abstract_generator.py | 8 +- 12 files changed, 157 insertions(+), 253 deletions(-) diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 6c0b55f8b132fb..b2476e1c6e5c4b 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -229,17 +229,15 @@ extern "C" { #define _GUARD_IS_NOT_NONE_POP 376 #define _JUMP_TO_TOP 377 #define _SAVE_RETURN_OFFSET 378 -#define _JUMP_ABSOLUTE 379 -#define _JUMP_ABSOLUTE_HEADER 380 -#define _CHECK_VALIDITY 381 -#define _LOAD_CONST_INLINE 382 -#define _LOAD_CONST_INLINE_BORROW 383 -#define _LOAD_CONST_INLINE_WITH_NULL 384 -#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 385 -#define _CHECK_GLOBALS 386 -#define _CHECK_BUILTINS 387 -#define _INTERNAL_INCREMENT_OPT_COUNTER 388 -#define MAX_UOP_ID 388 +#define _CHECK_VALIDITY 379 +#define _LOAD_CONST_INLINE 380 +#define _LOAD_CONST_INLINE_BORROW 381 +#define _LOAD_CONST_INLINE_WITH_NULL 382 +#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 383 +#define _CHECK_GLOBALS 384 +#define _CHECK_BUILTINS 385 +#define _INTERNAL_INCREMENT_OPT_COUNTER 386 +#define MAX_UOP_ID 386 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index f0a278cbfe4902..30dc5a881574e7 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -201,8 +201,6 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_SET_IP] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, [_SAVE_RETURN_OFFSET] = HAS_ARG_FLAG, [_EXIT_TRACE] = HAS_DEOPT_FLAG, - [_JUMP_ABSOLUTE] = HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG, - [_JUMP_ABSOLUTE_HEADER] = 0, [_CHECK_VALIDITY] = HAS_DEOPT_FLAG, [_LOAD_CONST_INLINE] = HAS_PURE_FLAG, [_LOAD_CONST_INLINE_BORROW] = HAS_PURE_FLAG, @@ -321,8 +319,6 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_ITER_NEXT_LIST] = "_ITER_NEXT_LIST", [_ITER_NEXT_RANGE] = "_ITER_NEXT_RANGE", [_ITER_NEXT_TUPLE] = "_ITER_NEXT_TUPLE", - [_JUMP_ABSOLUTE] = "_JUMP_ABSOLUTE", - [_JUMP_ABSOLUTE_HEADER] = "_JUMP_ABSOLUTE_HEADER", [_JUMP_TO_TOP] = "_JUMP_TO_TOP", [_LIST_APPEND] = "_LIST_APPEND", [_LIST_EXTEND] = "_LIST_EXTEND", diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 481d5ef78c26d2..1b168552db973d 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -345,7 +345,7 @@ def testfunc(n): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) uops = {opname for opname, _, _ in ex} - self.assertIn("_JUMP_ABSOLUTE", uops) + self.assertIn("_JUMP_TO_TOP", uops) def test_jump_forward(self): def testfunc(n): @@ -662,30 +662,6 @@ def testfunc(n): uops = {opname for opname, _, _ in ex} self.assertNotIn("_BINARY_OP_ADD_INT", uops) - def test_loop_peeling(self): - def testfunc(loops): - num = 0 - for _ in range(loops): - x = 0 - y = 1 - a = x + y - return 1 - - opt = _testinternalcapi.get_uop_optimizer() - res = None - with temporary_optimizer(opt): - res = testfunc(64) - - ex = get_first_executor(testfunc) - self.assertIsNotNone(ex) - self.assertEqual(res, 1) - binop_count = [opname for opname, _, _ in ex if opname == "_BINARY_OP_ADD_INT"] - self.assertEqual(len(binop_count), 2) - uops = {opname for opname, _, _ in ex} - self.assertNotIn("_SHRINK_STACK", uops) - iter_next_count = [opname for opname, _, _ in ex if opname == "_ITER_NEXT_RANGE"] - self.assertLessEqual(len(iter_next_count), 2) - def test_call_py_exact_args_disappearing(self): def dummy(x): return x+1 diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index 0cb21531c00216..2c581692a5c928 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -176,12 +176,12 @@ _Py_UOpsSymType *left; right = stack_pointer[-1]; left = stack_pointer[-2]; - if (sym_matches_type(left, PYLONG_TYPE, 0) && - sym_matches_type(right, PYLONG_TYPE, 0)) { + if (sym_matches_pytype(left, &PyLong_Type, 0) && + sym_matches_pytype(right, &PyLong_Type, 0)) { REPLACE_OP(_NOP, 0, 0); } - sym_set_type(left, PYLONG_TYPE, 0); - sym_set_type(right, PYLONG_TYPE, 0); + sym_set_pytype(left, &PyLong_Type, 0); + sym_set_pytype(right, &PyLong_Type, 0); break; } @@ -207,7 +207,7 @@ if (res == NULL) { goto error; } - sym_set_type(res, PYLONG_TYPE, 0); + sym_set_pytype(res, &PyLong_Type, 0); stack_pointer[-2] = res; stack_pointer += -1; break; @@ -227,12 +227,12 @@ _Py_UOpsSymType *left; right = stack_pointer[-1]; left = stack_pointer[-2]; - if (sym_matches_type(left, PYFLOAT_TYPE, 0) && - sym_matches_type(right, PYFLOAT_TYPE, 0)) { + if (sym_matches_pytype(left, &PyFloat_Type, 0) && + sym_matches_pytype(right, &PyFloat_Type, 0)) { REPLACE_OP(_NOP, 0 ,0); } - sym_set_type(left, PYFLOAT_TYPE, 0); - sym_set_type(right, PYFLOAT_TYPE, 0); + sym_set_pytype(left, &PyFloat_Type, 0); + sym_set_pytype(right, &PyFloat_Type, 0); break; } @@ -241,7 +241,7 @@ res = sym_init_unknown(ctx); if (res == NULL) goto error; - sym_set_type(res, PYFLOAT_TYPE, 0); + sym_set_pytype(res, &PyFloat_Type, 0); stack_pointer[0] = res; stack_pointer += 1; break; @@ -252,7 +252,7 @@ res = sym_init_unknown(ctx); if (res == NULL) goto error; - sym_set_type(res, PYFLOAT_TYPE, 0); + sym_set_pytype(res, &PyFloat_Type, 0); stack_pointer[0] = res; stack_pointer += 1; break; @@ -263,7 +263,7 @@ res = sym_init_unknown(ctx); if (res == NULL) goto error; - sym_set_type(res, PYFLOAT_TYPE, 0); + sym_set_pytype(res, &PyFloat_Type, 0); stack_pointer[0] = res; stack_pointer += 1; break; @@ -275,8 +275,8 @@ right = stack_pointer[-1]; left = stack_pointer[-2]; - sym_set_type(left, PYUNICODE_TYPE, 0); - sym_set_type(right, PYUNICODE_TYPE, 0); + sym_set_pytype(left, &PyUnicode_Type, 0); + sym_set_pytype(right, &PyUnicode_Type, 0); break; } @@ -285,7 +285,7 @@ res = sym_init_unknown(ctx); if (res == NULL) goto error; - sym_set_type(res, PYUNICODE_TYPE, 0); + sym_set_pytype(res, &PyUnicode_Type, 0); stack_pointer[0] = res; stack_pointer += 1; break; @@ -1132,7 +1132,7 @@ if (next == NULL) goto error; (void)iter; - sym_set_type(next, PYLONG_TYPE, 0); + sym_set_pytype(next, &PyLong_Type, 0); stack_pointer[0] = next; stack_pointer += 1; break; @@ -1275,8 +1275,8 @@ null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - sym_set_type(callable, PYMETHOD_TYPE, 0); - sym_set_type(null, NULL_TYPE, 0); + sym_set_pytype(callable, &PyMethod_Type, 0); + sym_set_pytype(null, NULL, 0); break; } @@ -1294,11 +1294,6 @@ } case _CHECK_PEP_523: { - /* Setting the eval frame function invalidates - * all executors, so no need to check dynamically */ - if (_PyInterpreterState_GET()->eval_frame == NULL) { - REPLACE_OP(_NOP, 0, 0); - } break; } @@ -1309,7 +1304,7 @@ callable = stack_pointer[-2 - oparg]; uint32_t func_version = (uint32_t)inst->operand; - sym_set_type(callable, PYFUNCTION_TYPE_VERSION_TYPE, func_version); + sym_set_pytype(callable, &PyFunction_Type, func_version); (void)self_or_null; break; } @@ -1634,14 +1629,6 @@ break; } - case _JUMP_ABSOLUTE: { - break; - } - - case _JUMP_ABSOLUTE_HEADER: { - break; - } - case _CHECK_VALIDITY: { break; } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 9d95ec3fce2885..fbe7726d263d49 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -452,7 +452,7 @@ dummy_func( DEOPT_IF(!PyFloat_CheckExact(right)); } - pure op(_BINARY_OP_MULTIPLY_FLOAT, (left, right -- res: &PYFLOAT_TYPE)) { + pure op(_BINARY_OP_MULTIPLY_FLOAT, (left, right -- res: &PyFloat_Type)) { 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); } - pure op(_BINARY_OP_ADD_FLOAT, (left, right -- res: &PYFLOAT_TYPE)) { + pure op(_BINARY_OP_ADD_FLOAT, (left, right -- res: &PyFloat_Type)) { 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); } - pure op(_BINARY_OP_SUBTRACT_FLOAT, (left, right -- res: &PYFLOAT_TYPE)) { + pure op(_BINARY_OP_SUBTRACT_FLOAT, (left, right -- res: &PyFloat_Type)) { STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval - @@ -483,12 +483,12 @@ dummy_func( macro(BINARY_OP_SUBTRACT_FLOAT) = _GUARD_BOTH_FLOAT + unused/1 + _BINARY_OP_SUBTRACT_FLOAT; - op(_GUARD_BOTH_UNICODE, (left, right -- left: &PYUNICODE_TYPE, right: &PYUNICODE_TYPE)) { + op(_GUARD_BOTH_UNICODE, (left, right -- left: &PyUnicode_Type, right: &PyUnicode_Type)) { DEOPT_IF(!PyUnicode_CheckExact(left)); DEOPT_IF(!PyUnicode_CheckExact(right)); } - pure op(_BINARY_OP_ADD_UNICODE, (left, right -- res: &PYUNICODE_TYPE)) { + pure op(_BINARY_OP_ADD_UNICODE, (left, right -- res: &PyUnicode_Type)) { STAT_INC(BINARY_OP, hit); res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); @@ -2722,7 +2722,7 @@ dummy_func( DEOPT_IF(r->len <= 0); } - op(_ITER_NEXT_RANGE, (iter -- iter, next: &PYLONG_TYPE)) { + op(_ITER_NEXT_RANGE, (iter -- iter, next: &PyLong_Type)) { _PyRangeIterObject *r = (_PyRangeIterObject *)iter; assert(Py_TYPE(r) == &PyRangeIter_Type); assert(r->len > 0); @@ -3101,7 +3101,7 @@ dummy_func( macro(CALL) = _SPECIALIZE_CALL + unused/2 + _CALL; - op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- callable: &PYMETHOD_TYPE, null: &NULL_TYPE, unused[oparg])) { + op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- callable: &PyMethod_Type, null: &NULL, unused[oparg])) { DEOPT_IF(null != NULL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type); } @@ -3119,7 +3119,7 @@ dummy_func( DEOPT_IF(tstate->interp->eval_frame); } - op(_CHECK_FUNCTION_EXACT_ARGS, (func_version/2, callable, self_or_null, unused[oparg] -- callable: &(PYFUNCTION_TYPE_VERSION_TYPE + func_version), self_or_null, unused[oparg])) { + op(_CHECK_FUNCTION_EXACT_ARGS, (func_version/2, callable, self_or_null, unused[oparg] -- callable: &(PyFunction_Type + func_version), self_or_null, unused[oparg])) { DEOPT_IF(!PyFunction_Check(callable)); PyFunctionObject *func = (PyFunctionObject *)callable; DEOPT_IF(func->func_version != func_version); @@ -4065,14 +4065,6 @@ dummy_func( DEOPT_IF(1); } - op(_JUMP_ABSOLUTE, (--)) { - next_uop = current_executor->trace + oparg; - CHECK_EVAL_BREAKER(); - } - - op(_JUMP_ABSOLUTE_HEADER, (--)) { - } - op(_CHECK_VALIDITY, (--)) { TIER_TWO_ONLY DEOPT_IF(!current_executor->vm_data.valid); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 2f32b5275f42c8..7d48d6a05a17b0 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3384,17 +3384,6 @@ break; } - case _JUMP_ABSOLUTE: { - oparg = CURRENT_OPARG(); - next_uop = current_executor->trace + oparg; - CHECK_EVAL_BREAKER(); - break; - } - - case _JUMP_ABSOLUTE_HEADER: { - break; - } - case _CHECK_VALIDITY: { TIER_TWO_ONLY if (!current_executor->vm_data.valid) goto deoptimize; diff --git a/Python/jit.c b/Python/jit.c index 308bde86d063df..6b950c84b03523 100644 --- a/Python/jit.c +++ b/Python/jit.c @@ -298,16 +298,6 @@ emit(const StencilGroup *group, uint64_t patches[]) copy_and_patch((char *)patches[HoleValue_DATA], &group->data, patches); } -static size_t -calculate_jump_abs_offset(_PyUOpInstruction *trace, _PyUOpInstruction *jump_absolute) -{ - assert(jump_absolute->opcode == _JUMP_ABSOLUTE); - size_t total = 0; - for (int i = 0; i < jump_absolute->oparg; i++) { - total += stencil_groups[trace[i].opcode].code.body_size; - } - return total; -} // Compiles executor in-place. Don't forget to call _PyJIT_Free later! int @@ -340,13 +330,7 @@ _PyJIT_Compile(_PyExecutorObject *executor, _PyUOpInstruction *trace, size_t len // Think of patches as a dictionary mapping HoleValue to uint64_t: uint64_t patches[] = GET_PATCHES(); patches[HoleValue_CODE] = (uint64_t)code; - if (instruction->opcode == _JUMP_ABSOLUTE) { - assert(i + 1 == length); - patches[HoleValue_CONTINUE] = (uint64_t)memory + calculate_jump_abs_offset(trace, instruction); - } - else { - patches[HoleValue_CONTINUE] = (uint64_t)code + group->code.body_size; - }; + patches[HoleValue_CONTINUE] = (uint64_t)code + group->code.body_size; patches[HoleValue_DATA] = (uint64_t)data; patches[HoleValue_EXECUTOR] = (uint64_t)executor; patches[HoleValue_OPARG] = instruction->oparg; diff --git a/Python/optimizer.c b/Python/optimizer.c index fb4ab99d66a21e..8a53393128d2d8 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -724,7 +724,7 @@ compute_used(_PyUOpInstruction *buffer, uint32_t *used) } count++; int opcode = buffer[i].opcode; - if (opcode == _JUMP_TO_TOP || opcode == _EXIT_TRACE || opcode == _JUMP_ABSOLUTE) { + if (opcode == _JUMP_TO_TOP || opcode == _EXIT_TRACE) { continue; } /* All other micro-ops fall through, so i+1 is reachable */ @@ -765,8 +765,7 @@ make_executor_from_uops(_PyUOpInstruction *buffer, _PyBloomFilter *dependencies) executor->trace[dest] = buffer[i]; int opcode = buffer[i].opcode; if (opcode == _POP_JUMP_IF_FALSE || - opcode == _POP_JUMP_IF_TRUE || - opcode == _JUMP_ABSOLUTE) + opcode == _POP_JUMP_IF_TRUE) { /* The oparg of the target will already have been set to its new offset */ int oparg = executor->trace[dest].oparg; @@ -778,19 +777,6 @@ make_executor_from_uops(_PyUOpInstruction *buffer, _PyBloomFilter *dependencies) dest--; } assert(dest == -1); - // Rewrite backward jumps - if (executor->trace[length-1].opcode == _JUMP_ABSOLUTE) { - bool found = false; - for (int end = length - 1; end >= 0; end--) { - if (executor->trace[end].opcode == _JUMP_ABSOLUTE_HEADER) { - executor->trace[length-1].oparg = end + 1; - found = true; - break; - } - } - assert(found); - (void)found; - } _Py_ExecutorInit(executor, dependencies); #ifdef Py_DEBUG char *python_lltrace = Py_GETENV("PYTHON_LLTRACE"); diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 7b9dcd1832a5cc..a8597e8939a1fc 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -78,6 +78,7 @@ typedef enum { PYMETHOD_TYPE = 7, GUARD_DORV_VALUES_TYPE = 8, // Can't statically determine if self or null. + // We use this over default unknown to catch more errors. SELF_OR_NULL = 9, // Represents something from LOAD_CONST which is truly constant. @@ -108,9 +109,6 @@ typedef struct { typedef struct _Py_UOpsAbstractFrame { - // Symbolic version of co_consts - int sym_consts_len; - _Py_UOpsSymType **sym_consts; // Max stacklen int stack_len; int locals_len; @@ -160,25 +158,6 @@ typedef struct _Py_UOpsAbstractInterpContext { static inline _Py_UOpsSymType* sym_init_const(_Py_UOpsAbstractInterpContext *ctx, PyObject *const_val); -static inline _Py_UOpsSymType ** -create_sym_consts(_Py_UOpsAbstractInterpContext *ctx, PyObject *co_consts) -{ - Py_ssize_t co_const_len = PyTuple_GET_SIZE(co_consts); - _Py_UOpsSymType **sym_consts = ctx->limit - co_const_len; - ctx->limit -= co_const_len; - if (ctx->limit <= ctx->n_consumed) { - return NULL; - } - for (Py_ssize_t i = 0; i < co_const_len; i++) { - _Py_UOpsSymType *res = sym_init_const(ctx, PyTuple_GET_ITEM(co_consts, i)); - if (res == NULL) { - return NULL; - } - sym_consts[i] = res; - } - - return sym_consts; -} static inline _Py_UOpsSymType* sym_init_unknown(_Py_UOpsAbstractInterpContext *ctx); @@ -192,15 +171,9 @@ ctx_frame_new( int curr_stackentries ) { - _Py_UOpsSymType **sym_consts = create_sym_consts(ctx, co->co_consts); - if (sym_consts == NULL) { - return NULL; - } assert(ctx->curr_frame_depth < MAX_ABSTRACT_FRAME_DEPTH); _Py_UOpsAbstractFrame *frame = &ctx->frames[ctx->curr_frame_depth]; - frame->sym_consts = sym_consts; - frame->sym_consts_len = (int)Py_SIZE(co->co_consts); frame->stack_len = co->co_stacksize; frame->locals_len = co->co_nlocalsplus; @@ -325,7 +298,6 @@ ctx_frame_pop( assert(ctx->curr_frame_depth >= 1); ctx->frame = &ctx->frames[ctx->curr_frame_depth - 1]; - ctx->limit += frame->sym_consts_len; return 0; } @@ -383,37 +355,59 @@ sym_copy_immutable_type_info(_Py_UOpsSymType *from_sym, _Py_UOpsSymType *to_sym) } } -static void -sym_set_type_from_const(_Py_UOpsSymType *sym, PyObject *obj) -{ - PyTypeObject *tp = Py_TYPE(obj); - if (tp->tp_version_tag != 0) { - sym_set_type(sym, GUARD_TYPE_VERSION_TYPE, tp->tp_version_tag); - } - if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) { - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(obj); - if(_PyDictOrValues_IsValues(dorv)) { - sym_set_type(sym, GUARD_DORV_VALUES_TYPE, 0); - } +static _Py_UOpsSymExprTypeEnum +pytype_to_type(PyTypeObject *tp) +{ + _Py_UOpsSymExprTypeEnum typ = INVALID_TYPE; + if (tp == NULL) { + typ = NULL_TYPE; } - if (tp == &PyLong_Type) { - sym_set_type(sym, PYLONG_TYPE, 0); + else if (tp == &PyLong_Type) { + typ = PYLONG_TYPE; } else if (tp == &PyFloat_Type) { - sym_set_type(sym, PYFLOAT_TYPE, 0); + typ = PYFLOAT_TYPE; } else if (tp == &PyUnicode_Type) { - sym_set_type(sym, PYUNICODE_TYPE, 0); + typ = PYUNICODE_TYPE; } else if (tp == &PyFunction_Type) { + typ = PYFUNCTION_TYPE_VERSION_TYPE; + } + else if (tp == &PyMethod_Type) { + typ = PYMETHOD_TYPE; + } + return typ; +} + +static void +sym_set_pytype(_Py_UOpsSymType *sym, PyTypeObject *tp, uint64_t refinement) +{ + assert(tp == NULL || PyType_Check(tp)); + sym_set_type(sym, pytype_to_type(tp), refinement); +} + +static void +sym_set_type_from_const(_Py_UOpsSymType *sym, PyObject *obj) +{ + PyTypeObject *tp = Py_TYPE(obj); + + if (tp->tp_version_tag != 0) { + sym_set_type(sym, GUARD_TYPE_VERSION_TYPE, tp->tp_version_tag); + } + if (tp == &PyFunction_Type) { sym_set_type(sym, PYFUNCTION_TYPE_VERSION_TYPE, ((PyFunctionObject *)(obj))->func_version); } + else { + sym_set_pytype(sym, tp, 0); + } } + static inline _Py_UOpsSymType* sym_init_unknown(_Py_UOpsAbstractInterpContext *ctx) { @@ -473,6 +467,13 @@ sym_matches_type(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ, uint64_t ref return true; } +static inline bool +sym_matches_pytype(_Py_UOpsSymType *sym, PyTypeObject *typ, uint64_t refinement) +{ + assert(typ == NULL || PyType_Check(typ)); + return sym_matches_type(sym, pytype_to_type(typ), refinement); +} + static uint64_t sym_type_get_refinement(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ) { @@ -485,8 +486,7 @@ sym_type_get_refinement(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ) static inline bool op_is_end(uint32_t opcode) { - return opcode == _EXIT_TRACE || opcode == _JUMP_TO_TOP || - opcode == _JUMP_ABSOLUTE; + return opcode == _EXIT_TRACE || opcode == _JUMP_TO_TOP; } @@ -503,25 +503,13 @@ op_is_data_movement_only(uint32_t opcode) { return (opcode == _STORE_FAST || opcode == STORE_FAST_MAYBE_NULL); } - +#ifdef Py_DEBUG static inline bool is_const(_Py_UOpsSymType *expr) { return expr->const_val != NULL; } - -static inline PyObject * -get_const_borrow(_Py_UOpsSymType *expr) -{ - return expr->const_val; -} - -static inline PyObject * -get_const(_Py_UOpsSymType *expr) -{ - return Py_NewRef(expr->const_val); -} - +#endif static int clear_locals_type_info(_Py_UOpsAbstractInterpContext *ctx) { @@ -563,12 +551,13 @@ emit_i(uops_emitter *emitter, #ifndef Py_DEBUG -#define GETITEM(ctx, i) (ctx->frame->sym_consts[(i)]) +#define GETITEM(ctx, i) Py_UNREACHABLE(); #else static inline _Py_UOpsSymType * GETITEM(_Py_UOpsAbstractInterpContext *ctx, Py_ssize_t i) { - assert(i < ctx->frame->sym_consts_len); - return ctx->frame->sym_consts[i]; + // There should be no LOAD_CONST. It should be all + // replaced by peephole_opt. + Py_UNREACHABLE(); } #endif @@ -826,7 +815,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, } static int -uop_abstract_interpret( +uop_redundancy_eliminator( PyCodeObject *co, _PyUOpInstruction *trace, _PyUOpInstruction *new_trace, @@ -834,7 +823,6 @@ uop_abstract_interpret( int curr_stacklen ) { - bool did_loop_peel = false; _Py_UOpsAbstractInterpContext ctx; @@ -848,10 +836,8 @@ uop_abstract_interpret( _PyUOpInstruction *end = NULL; int status = 0; bool needs_clear_locals = true; - bool has_enough_space_to_duplicate_loop = true; int res = 0; -loop_peeling: curr = trace; end = trace + trace_len; needs_clear_locals = true; @@ -887,43 +873,10 @@ uop_abstract_interpret( assert(op_is_end(curr->opcode)); - // If we end in a loop, and we have a lot of space left, peel the loop for - // poor man's loop invariant code motion for guards - // https://en.wikipedia.org/wiki/Loop_splitting - has_enough_space_to_duplicate_loop = ((ctx.emitter.curr_i * 3) < - (int)(ctx.emitter.writebuffer_end - ctx.emitter.writebuffer)); - if (!did_loop_peel && curr->opcode == _JUMP_TO_TOP && has_enough_space_to_duplicate_loop) { - OPT_STAT_INC(loop_body_duplication_attempts); - did_loop_peel = true; - _PyUOpInstruction jump_header = {_JUMP_ABSOLUTE_HEADER, (ctx.emitter.curr_i), 0, 0}; - if (emit_i(&ctx.emitter, jump_header) < 0) { - goto error; - } - DPRINTF(1, "loop_peeling!\n"); - goto loop_peeling; - } - else { -#if defined(Py_STATS) || defined(Py_DEBUG) - if(!did_loop_peel && curr->opcode == _JUMP_TO_TOP && !has_enough_space_to_duplicate_loop) { - OPT_STAT_INC(loop_body_duplication_no_mem); - DPRINTF(1, "no space for loop peeling\n"); - } -#endif - if (did_loop_peel) { - OPT_STAT_INC(loop_body_duplication_successes); - assert(curr->opcode == _JUMP_TO_TOP); - _PyUOpInstruction jump_abs = {_JUMP_ABSOLUTE, (ctx.emitter.curr_i), 0, 0}; - if (emit_i(&ctx.emitter, jump_abs) < 0) { - goto error; - } - } else { - if (emit_i(&ctx.emitter, *curr) < 0) { - goto error; - } - } + if (emit_i(&ctx.emitter, *curr) < 0) { + goto error; } - res = ctx.emitter.curr_i; abstractcontext_fini(&ctx); @@ -973,6 +926,48 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size) } } +static void +peephole_opt(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, int buffer_size) +{ + PyCodeObject *co = (PyCodeObject *)frame->f_executable; + for (int pc = 0; pc < buffer_size; pc++) { + int opcode = buffer[pc].opcode; + switch(opcode) { + case _LOAD_CONST: { + assert(co != NULL); + PyObject *val = PyTuple_GET_ITEM(co->co_consts, buffer[pc].oparg); + buffer[pc].opcode = _Py_IsImmortal(val) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE; + buffer[pc].operand = (uintptr_t)val; + break; + } + case _CHECK_PEP_523: + { + /* Setting the eval frame function invalidates + * all executors, so no need to check dynamically */ + if (_PyInterpreterState_GET()->eval_frame == NULL) { + buffer[pc].opcode = _NOP; + } + break; + } + case _PUSH_FRAME: + case _POP_FRAME: + { + PyFunctionObject *func = (PyFunctionObject *)buffer[pc].operand; + if (func == NULL) { + co = NULL; + } + else { + assert(PyFunction_Check(func)); + co = (PyCodeObject *)func->func_code; + } + break; + } + case _JUMP_TO_TOP: + case _EXIT_TRACE: + return; + } + } +} // 0 - failure, no error raised, just fall back to Tier 1 // -1 - failure, and raise error @@ -994,8 +989,10 @@ _Py_uop_analyze_and_optimize( goto error; } + peephole_opt(frame, buffer, buffer_size); + // Pass: Abstract interpretation and symbolic analysis - int new_trace_len = uop_abstract_interpret( + int new_trace_len = uop_redundancy_eliminator( (PyCodeObject *)frame->f_executable, buffer, temp_writebuffer, buffer_size, curr_stacklen); @@ -1004,6 +1001,7 @@ _Py_uop_analyze_and_optimize( } + remove_unneeded_uops(temp_writebuffer, new_trace_len); // Fill in our new trace! diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index b774b6d4767b95..9873bee50a721a 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -65,22 +65,22 @@ dummy_func(void) { }; } - op(_GUARD_BOTH_INT, (left, right -- left: &PYLONG_TYPE, right: &PYLONG_TYPE)) { - if (sym_matches_type(left, PYLONG_TYPE, 0) && - sym_matches_type(right, PYLONG_TYPE, 0)) { + op(_GUARD_BOTH_INT, (left, right -- left: &PyLong_Type, right: &PyLong_Type)) { + if (sym_matches_pytype(left, &PyLong_Type, 0) && + sym_matches_pytype(right, &PyLong_Type, 0)) { REPLACE_OP(_NOP, 0, 0); } } - op(_GUARD_BOTH_FLOAT, (left, right -- left: &PYFLOAT_TYPE, right: &PYFLOAT_TYPE)) { - if (sym_matches_type(left, PYFLOAT_TYPE, 0) && - sym_matches_type(right, PYFLOAT_TYPE, 0)) { + op(_GUARD_BOTH_FLOAT, (left, right -- left: &PyFloat_Type, right: &PyFloat_Type)) { + if (sym_matches_pytype(left, &PyFloat_Type, 0) && + sym_matches_pytype(right, &PyFloat_Type, 0)) { REPLACE_OP(_NOP, 0 ,0); } } - op(_BINARY_OP_ADD_INT, (left, right -- res: &PYLONG_TYPE)) { + op(_BINARY_OP_ADD_INT, (left, right -- res: &PyLong_Type)) { // TODO constant propagation (void)left; (void)right; @@ -223,14 +223,6 @@ dummy_func(void) { } } - op(_CHECK_PEP_523, (--)) { - /* Setting the eval frame function invalidates - * all executors, so no need to check dynamically */ - if (_PyInterpreterState_GET()->eval_frame == NULL) { - REPLACE_OP(_NOP, 0, 0); - } - } - diff --git a/Tools/cases_generator/interpreter_definition.md b/Tools/cases_generator/interpreter_definition.md index a68d42690791e2..bb9e9deacbc585 100644 --- a/Tools/cases_generator/interpreter_definition.md +++ b/Tools/cases_generator/interpreter_definition.md @@ -160,7 +160,7 @@ and their refinements are below. They obey the following predicates: * `PYMETHOD_TYPE`: `Py_TYPE(val) == &PyMethod_Type` * `PYFUNCTION_TYPE_VERSION_TYPE`: `PyFunction_Check(callable) && func->func_version == auxillary && code->co_argcount == oparg + (self_or_null != NULL)` -* `SELF_OR_NULL`: `val == NULL || val != NULL` +* `SELF_OR_NULL`: `val == undetermistic` An `inst` without `stack_effect` is a transitional form to allow the original C code diff --git a/Tools/cases_generator/tier2_abstract_generator.py b/Tools/cases_generator/tier2_abstract_generator.py index 0eb4aaefdebc74..96cc1c63125115 100644 --- a/Tools/cases_generator/tier2_abstract_generator.py +++ b/Tools/cases_generator/tier2_abstract_generator.py @@ -153,7 +153,13 @@ def write_uop( if typ := output.type_prop: typname, refinement = typ refinement = refinement or "0" - out.emit(f"sym_set_type({output.name}, {typname}, {refinement});\n") + # Special enum types, not corresponding to a specific PyTypeObject + if typname.isupper() and typname != "NULL": + print(typname) + out.emit(f"sym_set_type({output.name}, {typname}, {refinement});\n") + else: + out.emit(f"sym_set_pytype({output.name}, " + f"{'&' if typname != 'NULL' else ''}{typname}, {refinement});\n") else: # Silence compiler unused variable warnings. if has_type_prop and output.name not in UNUSED: From e34a0f5cac17bf400480803128ed725238d37103 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 7 Feb 2024 15:40:49 +0800 Subject: [PATCH 11/52] reduce diff, add tests --- Lib/test/test_capi/test_opt.py | 28 ++++++++++++++++++++++++---- Python/optimizer_analysis.c | 2 +- Python/pylifecycle.c | 2 +- Tools/cases_generator/analyzer.py | 1 + 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 1b168552db973d..c719f723c3b75a 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -568,6 +568,30 @@ def testfunc(loops): self.assertGreaterEqual(len(binop_count), 3) self.assertLessEqual(len(guard_both_int_count), 1) + def test_int_type_propagation_through_frame(self): + def double(x): + return x + x + def testfunc(loops): + num = 0 + while num < loops: + x = num + num + a = double(x) + num += 1 + return a + + opt = _testinternalcapi.get_uop_optimizer() + res = None + with temporary_optimizer(opt): + res = testfunc(32) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + self.assertEqual(res, 124) + binop_count = [opname for opname, _, _ in ex if opname == "_BINARY_OP_ADD_INT"] + guard_both_int_count = [opname for opname, _, _ in ex if opname == "_GUARD_BOTH_INT"] + self.assertGreaterEqual(len(binop_count), 3) + self.assertLessEqual(len(guard_both_int_count), 1) + def test_int_impure_region(self): def testfunc(loops): num = 0 @@ -705,9 +729,5 @@ def testfunc(n): -class Foo: - attr = 1 - - if __name__ == "__main__": unittest.main() diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index a8597e8939a1fc..f66fa702c70819 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -551,7 +551,7 @@ emit_i(uops_emitter *emitter, #ifndef Py_DEBUG -#define GETITEM(ctx, i) Py_UNREACHABLE(); +#define GETITEM(ctx, i) (_Py_UOpsSymType *)Py_UNREACHABLE(); #else static inline _Py_UOpsSymType * GETITEM(_Py_UOpsAbstractInterpContext *ctx, Py_ssize_t i) { diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index bf6bf66c243534..6c042425423640 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1252,7 +1252,7 @@ init_interp_main(PyThreadState *tstate) if (_Py_get_xoption(&config->xoptions, L"uops") != NULL) { enabled = 1; } - enabled = 1; // TEMPORARY: always enable + if (enabled) { #else // Always enable tier two for JIT builds (ignoring the environment diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index 3b5deff12ff1dd..b0c57fae46a6e4 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -3,6 +3,7 @@ import parser from typing import Optional + @dataclass class Properties: escapes: bool From 229aab023cb3e80c00a1918a66c322d560283d66 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 7 Feb 2024 15:46:25 +0800 Subject: [PATCH 12/52] fix compilation problems --- Python/abstract_interp_cases.c.h | 4 +++- Python/optimizer_analysis.c | 13 ------------- Python/tier2_redundancy_eliminator_bytecodes.c | 4 +++- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index 2c581692a5c928..2c360d8db570c5 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -48,7 +48,9 @@ case _LOAD_CONST: { _Py_UOpsSymType *value; - value = GETITEM(ctx, oparg); + // There should be no LOAD_CONST. It should be all + // replaced by peephole_opt. + Py_UNREACHABLE(); stack_pointer[0] = value; stack_pointer += 1; break; diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index f66fa702c70819..2dc7a0def23efa 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -548,19 +548,6 @@ emit_i(uops_emitter *emitter, return 0; } - - -#ifndef Py_DEBUG -#define GETITEM(ctx, i) (_Py_UOpsSymType *)Py_UNREACHABLE(); -#else -static inline _Py_UOpsSymType * -GETITEM(_Py_UOpsAbstractInterpContext *ctx, Py_ssize_t i) { - // There should be no LOAD_CONST. It should be all - // replaced by peephole_opt. - Py_UNREACHABLE(); -} -#endif - static int uop_abstract_interpret_single_inst( _PyUOpInstruction *inst, diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index 9873bee50a721a..b181671058c5e5 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -91,7 +91,9 @@ dummy_func(void) { } op(_LOAD_CONST, (-- value)) { - value = GETITEM(ctx, oparg); + // There should be no LOAD_CONST. It should be all + // replaced by peephole_opt. + Py_UNREACHABLE(); } op(_LOAD_CONST_INLINE, (ptr/4 -- value)) { From 3c8def4ada475b9a81133c226c4b72afcc579c67 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 7 Feb 2024 16:12:36 +0800 Subject: [PATCH 13/52] don't needlessly clear aliasing information --- Lib/test/test_capi/test_opt.py | 24 ++++++++++++++++++++++++ Python/jit.c | 1 - Python/optimizer_analysis.c | 12 +++++------- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index c719f723c3b75a..8e100a35047dbb 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -592,6 +592,30 @@ def testfunc(loops): self.assertGreaterEqual(len(binop_count), 3) self.assertLessEqual(len(guard_both_int_count), 1) + def test_int_type_propagation_from_frame(self): + def double(x): + return x + x + def testfunc(loops): + num = 0 + while num < loops: + a = double(num) + x = a + a + num += 1 + return x + + opt = _testinternalcapi.get_uop_optimizer() + res = None + with temporary_optimizer(opt): + res = testfunc(32) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + self.assertEqual(res, 124) + binop_count = [opname for opname, _, _ in ex if opname == "_BINARY_OP_ADD_INT"] + guard_both_int_count = [opname for opname, _, _ in ex if opname == "_GUARD_BOTH_INT"] + self.assertGreaterEqual(len(binop_count), 3) + self.assertLessEqual(len(guard_both_int_count), 1) + def test_int_impure_region(self): def testfunc(loops): num = 0 diff --git a/Python/jit.c b/Python/jit.c index 6b950c84b03523..22949c082da05a 100644 --- a/Python/jit.c +++ b/Python/jit.c @@ -298,7 +298,6 @@ emit(const StencilGroup *group, uint64_t patches[]) copy_and_patch((char *)patches[HoleValue_DATA], &group->data, patches); } - // Compiles executor in-place. Don't forget to call _PyJIT_Free later! int _PyJIT_Compile(_PyExecutorObject *executor, _PyUOpInstruction *trace, size_t length) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 2dc7a0def23efa..f0af2f3cc0be32 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -500,7 +500,10 @@ op_is_bookkeeping(uint32_t opcode) { static inline bool op_is_data_movement_only(uint32_t opcode) { - return (opcode == _STORE_FAST || opcode == STORE_FAST_MAYBE_NULL); + return (opcode == _STORE_FAST || + opcode == STORE_FAST_MAYBE_NULL || + opcode == _PUSH_FRAME || + opcode == _POP_FRAME); } #ifdef Py_DEBUG @@ -515,12 +518,7 @@ static int clear_locals_type_info(_Py_UOpsAbstractInterpContext *ctx) { int locals_entries = ctx->frame->locals_len; for (int i = 0; i < locals_entries; i++) { - _Py_UOpsSymType *new_local = sym_init_unknown(ctx); - if (new_local == NULL) { - return -1; - } - sym_copy_immutable_type_info(ctx->frame->locals[i], new_local); - ctx->frame->locals[i] = new_local; + sym_copy_immutable_type_info(ctx->frame->locals[i], ctx->frame->locals[i]); } return 0; } From 649b0c7d6a20410c1320e5eeb28af27c8d760781 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 7 Feb 2024 16:14:42 +0800 Subject: [PATCH 14/52] remove is_const for now --- Python/abstract_interp_cases.c.h | 4 ---- Python/optimizer_analysis.c | 7 ------- Python/tier2_redundancy_eliminator_bytecodes.c | 4 ---- 3 files changed, 15 deletions(-) diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index 2c360d8db570c5..e27a45abc827e2 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -1643,7 +1643,6 @@ goto error; } value = sym_const; - assert(is_const(value)); stack_pointer[0] = value; stack_pointer += 1; break; @@ -1657,7 +1656,6 @@ goto error; } value = sym_const; - assert(is_const(value)); stack_pointer[0] = value; stack_pointer += 1; break; @@ -1672,7 +1670,6 @@ goto error; } value = sym_const; - assert(is_const(value)); _Py_UOpsSymType *null_sym = sym_init_null(ctx); if (null_sym == NULL) { goto error; @@ -1693,7 +1690,6 @@ goto error; } value = sym_const; - assert(is_const(value)); _Py_UOpsSymType *null_sym = sym_init_null(ctx); if (null_sym == NULL) { goto error; diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index f0af2f3cc0be32..9798e09d7746f2 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -506,13 +506,6 @@ op_is_data_movement_only(uint32_t opcode) { opcode == _POP_FRAME); } -#ifdef Py_DEBUG -static inline bool -is_const(_Py_UOpsSymType *expr) -{ - return expr->const_val != NULL; -} -#endif static int clear_locals_type_info(_Py_UOpsAbstractInterpContext *ctx) { diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index b181671058c5e5..1497c3271bbf65 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -102,7 +102,6 @@ dummy_func(void) { goto error; } value = sym_const; - assert(is_const(value)); } op(_LOAD_CONST_INLINE_BORROW, (ptr/4 -- value)) { @@ -111,7 +110,6 @@ dummy_func(void) { goto error; } value = sym_const; - assert(is_const(value)); } op(_LOAD_CONST_INLINE_WITH_NULL, (ptr/4 -- value, null)) { @@ -120,7 +118,6 @@ dummy_func(void) { goto error; } value = sym_const; - assert(is_const(value)); _Py_UOpsSymType *null_sym = sym_init_null(ctx); if (null_sym == NULL) { goto error; @@ -134,7 +131,6 @@ dummy_func(void) { goto error; } value = sym_const; - assert(is_const(value)); _Py_UOpsSymType *null_sym = sym_init_null(ctx); if (null_sym == NULL) { goto error; From 2805755bfb09293d7c0537e845bb61657ef6e67b Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 7 Feb 2024 20:33:29 +0800 Subject: [PATCH 15/52] remove type prop (address review) --- Python/abstract_interp_cases.c.h | 57 ++++--------------- Python/bytecodes.c | 24 ++++---- Python/optimizer_analysis.c | 38 ++++++++++--- Python/pylifecycle.c | 2 +- .../tier2_redundancy_eliminator_bytecodes.c | 36 +++++++++--- Tools/cases_generator/analyzer.py | 2 +- .../cases_generator/interpreter_definition.md | 25 +------- Tools/cases_generator/parsing.py | 26 ++------- .../tier2_abstract_generator.py | 30 ++-------- 9 files changed, 95 insertions(+), 145 deletions(-) diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index e27a45abc827e2..46bc87668ff1ed 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -205,11 +205,10 @@ // TODO constant propagation (void)left; (void)right; - res = sym_init_unknown(ctx); + res = sym_init_known_pytype(ctx, &PyLong_Type, 0); if (res == NULL) { goto error; } - sym_set_pytype(res, &PyLong_Type, 0); stack_pointer[-2] = res; stack_pointer += -1; break; @@ -242,8 +241,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - - sym_set_pytype(res, &PyFloat_Type, 0); stack_pointer[0] = res; stack_pointer += 1; break; @@ -253,8 +250,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - - sym_set_pytype(res, &PyFloat_Type, 0); stack_pointer[0] = res; stack_pointer += 1; break; @@ -264,21 +259,12 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - - sym_set_pytype(res, &PyFloat_Type, 0); stack_pointer[0] = res; stack_pointer += 1; break; } case _GUARD_BOTH_UNICODE: { - _Py_UOpsSymType *left; - _Py_UOpsSymType *right; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - - sym_set_pytype(left, &PyUnicode_Type, 0); - sym_set_pytype(right, &PyUnicode_Type, 0); break; } @@ -286,8 +272,6 @@ _Py_UOpsSymType *res; res = sym_init_unknown(ctx); if (res == NULL) goto error; - - sym_set_pytype(res, &PyUnicode_Type, 0); stack_pointer[0] = res; stack_pointer += 1; break; @@ -785,9 +769,6 @@ if (attr == NULL) goto error; self_or_null = sym_init_unknown(ctx); if (self_or_null == NULL) goto error; - - (void)attr; - sym_set_type(self_or_null, SELF_OR_NULL, 0); stack_pointer[0] = attr; if (oparg & 1) stack_pointer[1] = self_or_null; stack_pointer += 1 + (oparg & 1); @@ -795,11 +776,6 @@ } case _GUARD_TYPE_VERSION: { - _Py_UOpsSymType *owner; - owner = stack_pointer[-1]; - uint32_t type_version = (uint32_t)inst->operand; - - sym_set_type(owner, GUARD_TYPE_VERSION_TYPE, type_version); break; } @@ -894,10 +870,6 @@ /* _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN is not a viable micro-op for tier 2 */ case _GUARD_DORV_VALUES: { - _Py_UOpsSymType *owner; - owner = stack_pointer[-1]; - - sym_set_type(owner, GUARD_DORV_VALUES_TYPE, 0); break; } @@ -1130,11 +1102,11 @@ _Py_UOpsSymType *iter; _Py_UOpsSymType *next; iter = stack_pointer[-1]; - next = sym_init_unknown(ctx); - if (next == NULL) goto error; - + next = sym_init_known_pytype(ctx, &PyLong_Type, 0); + if (next == NULL) { + goto error; + } (void)iter; - sym_set_pytype(next, &PyLong_Type, 0); stack_pointer[0] = next; stack_pointer += 1; break; @@ -1195,11 +1167,6 @@ } case _GUARD_KEYS_VERSION: { - _Py_UOpsSymType *owner; - owner = stack_pointer[-1]; - uint32_t keys_version = (uint32_t)inst->operand; - - sym_set_type(owner, GUARD_KEYS_VERSION_TYPE, keys_version); break; } @@ -1272,13 +1239,12 @@ /* _CALL is not a viable micro-op for tier 2 */ case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: { - _Py_UOpsSymType *callable; _Py_UOpsSymType *null; + _Py_UOpsSymType *callable; null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - - sym_set_pytype(callable, &PyMethod_Type, 0); sym_set_pytype(null, NULL, 0); + sym_set_pytype(callable, &PyMethod_Type, 0); break; } @@ -1300,12 +1266,11 @@ } case _CHECK_FUNCTION_EXACT_ARGS: { - _Py_UOpsSymType *callable; _Py_UOpsSymType *self_or_null; + _Py_UOpsSymType *callable; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; uint32_t func_version = (uint32_t)inst->operand; - sym_set_pytype(callable, &PyFunction_Type, func_version); (void)self_or_null; break; @@ -1331,8 +1296,8 @@ PyCodeObject *co = (PyCodeObject *)func->func_code; assert(self_or_null != NULL); assert(args != NULL); - if (!sym_is_type(self_or_null, NULL_TYPE) && - !sym_is_type(self_or_null, SELF_OR_NULL)) { + if (!sym_matches_pytype(self_or_null, NULL, 0) && + !sym_is_unknown_type(self_or_null)) { // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in // VM args--; @@ -1343,7 +1308,7 @@ // Can determine statically, so we interleave the new locals // and make the current stack the new locals. // This also sets up for true call inlining. - if (!sym_is_type(self_or_null, SELF_OR_NULL)) { + if (!sym_is_unknown_type(self_or_null)) { localsplus_start = args; n_locals_already_filled = argcount; } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index fbe7726d263d49..1939ba6fca6552 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -452,7 +452,7 @@ dummy_func( DEOPT_IF(!PyFloat_CheckExact(right)); } - pure op(_BINARY_OP_MULTIPLY_FLOAT, (left, right -- res: &PyFloat_Type)) { + pure 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); } - pure op(_BINARY_OP_ADD_FLOAT, (left, right -- res: &PyFloat_Type)) { + pure 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); } - pure op(_BINARY_OP_SUBTRACT_FLOAT, (left, right -- res: &PyFloat_Type)) { + pure op(_BINARY_OP_SUBTRACT_FLOAT, (left, right -- res)) { STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval - @@ -483,12 +483,12 @@ dummy_func( macro(BINARY_OP_SUBTRACT_FLOAT) = _GUARD_BOTH_FLOAT + unused/1 + _BINARY_OP_SUBTRACT_FLOAT; - op(_GUARD_BOTH_UNICODE, (left, right -- left: &PyUnicode_Type, right: &PyUnicode_Type)) { + op(_GUARD_BOTH_UNICODE, (left, right -- left, right)) { DEOPT_IF(!PyUnicode_CheckExact(left)); DEOPT_IF(!PyUnicode_CheckExact(right)); } - pure op(_BINARY_OP_ADD_UNICODE, (left, right -- res: &PyUnicode_Type)) { + pure op(_BINARY_OP_ADD_UNICODE, (left, right -- res)) { STAT_INC(BINARY_OP, hit); res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); @@ -1859,7 +1859,7 @@ dummy_func( #endif /* ENABLE_SPECIALIZATION */ } - op(_LOAD_ATTR, (owner -- attr, self_or_null: &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. */ @@ -1901,7 +1901,7 @@ dummy_func( LOAD_ATTR, }; - op(_GUARD_TYPE_VERSION, (type_version/2, owner -- owner: &(GUARD_TYPE_VERSION_TYPE + type_version))) { + op(_GUARD_TYPE_VERSION, (type_version/2, owner -- owner)) { PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version); @@ -2082,7 +2082,7 @@ dummy_func( DISPATCH_INLINED(new_frame); } - op(_GUARD_DORV_VALUES, (owner -- owner: &GUARD_DORV_VALUES_TYPE)) { + op(_GUARD_DORV_VALUES, (owner -- owner)) { assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); DEOPT_IF(!_PyDictOrValues_IsValues(dorv)); @@ -2722,7 +2722,7 @@ dummy_func( DEOPT_IF(r->len <= 0); } - op(_ITER_NEXT_RANGE, (iter -- iter, next: &PyLong_Type)) { + op(_ITER_NEXT_RANGE, (iter -- iter, next)) { _PyRangeIterObject *r = (_PyRangeIterObject *)iter; assert(Py_TYPE(r) == &PyRangeIter_Type); assert(r->len > 0); @@ -2886,7 +2886,7 @@ dummy_func( DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && !_PyObject_MakeInstanceAttributesFromDict(owner, dorv)); } - op(_GUARD_KEYS_VERSION, (keys_version/2, owner -- owner: &(GUARD_KEYS_VERSION_TYPE + keys_version))) { + op(_GUARD_KEYS_VERSION, (keys_version/2, owner -- owner)) { PyTypeObject *owner_cls = Py_TYPE(owner); PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version != keys_version); @@ -3101,7 +3101,7 @@ dummy_func( macro(CALL) = _SPECIALIZE_CALL + unused/2 + _CALL; - op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- callable: &PyMethod_Type, null: &NULL, unused[oparg])) { + op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- callable, null, unused[oparg])) { DEOPT_IF(null != NULL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type); } @@ -3119,7 +3119,7 @@ dummy_func( DEOPT_IF(tstate->interp->eval_frame); } - op(_CHECK_FUNCTION_EXACT_ARGS, (func_version/2, callable, self_or_null, unused[oparg] -- callable: &(PyFunction_Type + func_version), self_or_null, unused[oparg])) { + op(_CHECK_FUNCTION_EXACT_ARGS, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { DEOPT_IF(!PyFunction_Check(callable)); PyFunctionObject *func = (PyFunctionObject *)callable; DEOPT_IF(func->func_version != func_version); diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 9798e09d7746f2..3afe2a66517be6 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -59,7 +59,18 @@ #define DPRINTF(level, ...) #endif -// See the interpreter DSL in ./Tools/cases_generator/interpreter_definition.md for what these correspond to. +/** +* `PYLONG_TYPE`: `Py_TYPE(val) == &PyLong_Type` +* `PYFLOAT_TYPE`: `Py_TYPE(val) == &PyFloat_Type` +* `PYUNICODE_TYPE`: `Py_TYPE(val) == &PYUNICODE_TYPE` +* `NULL_TYPE`: `val == NULL` +* `GUARD_TYPE_VERSION_TYPE`: `type->tp_version_tag == auxillary` +* `GUARD_DORV_VALUES_TYPE`: `_PyDictOrValues_IsValues(obj)` +* `GUARD_KEYS_VERSION_TYPE`: `owner_heap_type->ht_cached_keys->dk_version == auxillary` +* `PYMETHOD_TYPE`: `Py_TYPE(val) == &PyMethod_Type` +* `PYFUNCTION_TYPE_VERSION_TYPE`: + `PyFunction_Check(callable) && func->func_version == auxillary && code->co_argcount == oparg + (self_or_null != NULL)` + */ typedef enum { // Types with refinement info GUARD_KEYS_VERSION_TYPE = 0, @@ -77,9 +88,6 @@ typedef enum { NULL_TYPE = 6, PYMETHOD_TYPE = 7, GUARD_DORV_VALUES_TYPE = 8, - // Can't statically determine if self or null. - // We use this over default unknown to catch more errors. - SELF_OR_NULL = 9, // Represents something from LOAD_CONST which is truly constant. TRUE_CONST = 30, @@ -94,7 +102,6 @@ static const uint32_t IMMUTABLES = 1 << PYLONG_TYPE | 1 << PYFLOAT_TYPE | 1 << PYUNICODE_TYPE | - 1 << SELF_OR_NULL | 1 << TRUE_CONST ); @@ -406,14 +413,24 @@ sym_set_type_from_const(_Py_UOpsSymType *sym, PyObject *obj) } - - static inline _Py_UOpsSymType* sym_init_unknown(_Py_UOpsAbstractInterpContext *ctx) { return _Py_UOpsSymType_New(ctx,NULL); } +static inline _Py_UOpsSymType* +sym_init_known_pytype(_Py_UOpsAbstractInterpContext *ctx, + PyTypeObject *typ, uint64_t refinement) +{ + _Py_UOpsSymType *res = _Py_UOpsSymType_New(ctx,NULL); + if (res == NULL) { + return NULL; + } + sym_set_pytype(res, typ, refinement); + return res; +} + // Takes a borrowed reference to const_val. static inline _Py_UOpsSymType* sym_init_const(_Py_UOpsAbstractInterpContext *ctx, PyObject *const_val) @@ -474,6 +491,12 @@ sym_matches_pytype(_Py_UOpsSymType *sym, PyTypeObject *typ, uint64_t refinement) return sym_matches_type(sym, pytype_to_type(typ), refinement); } +static inline bool +sym_is_unknown_type(_Py_UOpsSymType *sym) +{ + return sym->types == 0 || (sym->types == 1U << INVALID_TYPE); +} + static uint64_t sym_type_get_refinement(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ) { @@ -969,7 +992,6 @@ _Py_uop_analyze_and_optimize( peephole_opt(frame, buffer, buffer_size); - // Pass: Abstract interpretation and symbolic analysis int new_trace_len = uop_redundancy_eliminator( (PyCodeObject *)frame->f_executable, buffer, temp_writebuffer, buffer_size, curr_stacklen); diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 6c042425423640..11ceaae05879a1 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1252,7 +1252,7 @@ init_interp_main(PyThreadState *tstate) if (_Py_get_xoption(&config->xoptions, L"uops") != NULL) { enabled = 1; } - + enabled = 1; if (enabled) { #else // Always enable tier two for JIT builds (ignoring the environment diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index 1497c3271bbf65..33ae4d1829e6cd 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -65,26 +65,30 @@ dummy_func(void) { }; } - op(_GUARD_BOTH_INT, (left, right -- left: &PyLong_Type, right: &PyLong_Type)) { + op(_GUARD_BOTH_INT, (left, right -- left, right)) { if (sym_matches_pytype(left, &PyLong_Type, 0) && sym_matches_pytype(right, &PyLong_Type, 0)) { REPLACE_OP(_NOP, 0, 0); } + sym_set_pytype(left, &PyLong_Type, 0); + sym_set_pytype(right, &PyLong_Type, 0); } - op(_GUARD_BOTH_FLOAT, (left, right -- left: &PyFloat_Type, right: &PyFloat_Type)) { + op(_GUARD_BOTH_FLOAT, (left, right -- left, right)) { if (sym_matches_pytype(left, &PyFloat_Type, 0) && sym_matches_pytype(right, &PyFloat_Type, 0)) { REPLACE_OP(_NOP, 0 ,0); } + sym_set_pytype(left, &PyFloat_Type, 0); + sym_set_pytype(right, &PyFloat_Type, 0); } - op(_BINARY_OP_ADD_INT, (left, right -- res: &PyLong_Type)) { + op(_BINARY_OP_ADD_INT, (left, right -- res)) { // TODO constant propagation (void)left; (void)right; - res = sym_init_unknown(ctx); + res = sym_init_known_pytype(ctx, &PyLong_Type, 0); if (res == NULL) { goto error; } @@ -148,6 +152,16 @@ dummy_func(void) { top, unused[oparg-2], bottom)) { } + op(_CHECK_FUNCTION_EXACT_ARGS, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { + sym_set_pytype(callable, &PyFunction_Type, func_version); + (void)self_or_null; + } + + op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- callable, null, unused[oparg])) { + sym_set_pytype(null, NULL, 0); + sym_set_pytype(callable, &PyMethod_Type, 0); + } + op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null, args[oparg] -- new_frame: _Py_UOpsAbstractFrame *)) { int argcount = oparg; @@ -159,8 +173,8 @@ dummy_func(void) { assert(self_or_null != NULL); assert(args != NULL); - if (!sym_is_type(self_or_null, NULL_TYPE) && - !sym_is_type(self_or_null, SELF_OR_NULL)) { + if (!sym_matches_pytype(self_or_null, NULL, 0) && + !sym_is_unknown_type(self_or_null)) { // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in // VM args--; @@ -172,7 +186,7 @@ dummy_func(void) { // Can determine statically, so we interleave the new locals // and make the current stack the new locals. // This also sets up for true call inlining. - if (!sym_is_type(self_or_null, SELF_OR_NULL)) { + if (!sym_is_unknown_type(self_or_null)) { localsplus_start = args; n_locals_already_filled = argcount; } @@ -221,6 +235,14 @@ dummy_func(void) { } } + op(_ITER_NEXT_RANGE, (iter -- iter, next)) { + next = sym_init_known_pytype(ctx, &PyLong_Type, 0); + if (next == NULL) { + goto error; + } + (void)iter; + } + diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index b0c57fae46a6e4..3497b7fcdf35d3 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -270,7 +270,7 @@ def override_error( def convert_stack_item(item: parser.StackEffect) -> StackItem: return StackItem( - item.name, item.type, item.cond, (item.size or "1"), type_prop=item.type_prop + item.name, item.type, item.cond, (item.size or "1") ) diff --git a/Tools/cases_generator/interpreter_definition.md b/Tools/cases_generator/interpreter_definition.md index bb9e9deacbc585..9b5733562f77b4 100644 --- a/Tools/cases_generator/interpreter_definition.md +++ b/Tools/cases_generator/interpreter_definition.md @@ -109,10 +109,7 @@ and a piece of C code describing its semantics:: NAME [":" type] [ "if" "(" C-expression ")" ] type: - NAME ["*"] | type_prop - - type_prop: - "&" "(" NAME ["+" NAME] ")" + NAME ["*"] stream: NAME "/" size @@ -142,25 +139,7 @@ The following definitions may occur: The optional `type` in an `object` is the C type. It defaults to `PyObject *`. The objects before the "--" are the objects on top of the stack at the start of the instruction. Those after the "--" are the objects on top of the stack at the -end of the instruction. When prefixed by a `&`, the `type` production rule follows the -`type_prop` production rule. This indicates the type of the value is of that specific type -after the operation. In this case, the type may also contain 64-bit refinement information -that is fetched from a previously defined operand in the instruction header, such as -a type version tag. This follows the format `type + refinement`. The list of possible types -and their refinements are below. They obey the following predicates: - - -* `PYLONG_TYPE`: `Py_TYPE(val) == &PyLong_Type` -* `PYFLOAT_TYPE`: `Py_TYPE(val) == &PyFloat_Type` -* `PYUNICODE_TYPE`: `Py_TYPE(val) == &PYUNICODE_TYPE` -* `NULL_TYPE`: `val == NULL` -* `GUARD_TYPE_VERSION_TYPE`: `type->tp_version_tag == auxillary` -* `GUARD_DORV_VALUES_TYPE`: `_PyDictOrValues_IsValues(obj)` -* `GUARD_KEYS_VERSION_TYPE`: `owner_heap_type->ht_cached_keys->dk_version == auxillary` -* `PYMETHOD_TYPE`: `Py_TYPE(val) == &PyMethod_Type` -* `PYFUNCTION_TYPE_VERSION_TYPE`: - `PyFunction_Check(callable) && func->func_version == auxillary && code->co_argcount == oparg + (self_or_null != NULL)` -* `SELF_OR_NULL`: `val == undetermistic` +end of the instruction. An `inst` without `stack_effect` is a transitional form to allow the original C code diff --git a/Tools/cases_generator/parsing.py b/Tools/cases_generator/parsing.py index 307919cb37ce1e..a8961f28babea1 100644 --- a/Tools/cases_generator/parsing.py +++ b/Tools/cases_generator/parsing.py @@ -75,11 +75,6 @@ class StackEffect(Node): size: str = "" # Optional `[size]` # Note: size cannot be combined with type or cond - # Optional `(type, refinement)` - type_prop: None | tuple[str, None | str] = field( - default_factory=lambda: None, init=True, compare=False, hash=False - ) - def __repr__(self) -> str: items = [self.name, self.type, self.cond, self.size] while items and items[-1] == "": @@ -260,25 +255,14 @@ def cache_effect(self) -> CacheEffect | None: @contextual def stack_effect(self) -> StackEffect | None: - # IDENTIFIER [':' [IDENTIFIER [TIMES]] ['&' '(' IDENTIFIER ['+' IDENTIFIER] ')']] ['if' '(' expression ')'] + # IDENTIFIER [':' IDENTIFIER [TIMES]] ['if' '(' expression ')'] # | IDENTIFIER '[' expression ']' if tkn := self.expect(lx.IDENTIFIER): type_text = "" - type_prop = None if self.expect(lx.COLON): - if i := self.expect(lx.IDENTIFIER): - type_text = i.text.strip() - if self.expect(lx.TIMES): - type_text += " *" - if self.expect(lx.AND): - consumed_bracket = self.expect(lx.LPAREN) is not None - type_prop_text = self.require(lx.IDENTIFIER).text.strip() - refinement = None - if self.expect(lx.PLUS): - refinement = self.require(lx.IDENTIFIER).text.strip() - type_prop = (type_prop_text, refinement) - if consumed_bracket: - self.require(lx.RPAREN) + type_text = self.require(lx.IDENTIFIER).text.strip() + if self.expect(lx.TIMES): + type_text += " *" cond_text = "" if self.expect(lx.IF): self.require(lx.LPAREN) @@ -295,7 +279,7 @@ def stack_effect(self) -> StackEffect | None: self.require(lx.RBRACKET) type_text = "PyObject **" size_text = size.text.strip() - return StackEffect(tkn.text, type_text, cond_text, size_text, type_prop) + return StackEffect(tkn.text, type_text, cond_text, size_text) return None @contextual diff --git a/Tools/cases_generator/tier2_abstract_generator.py b/Tools/cases_generator/tier2_abstract_generator.py index 96cc1c63125115..559b610b8ab5ca 100644 --- a/Tools/cases_generator/tier2_abstract_generator.py +++ b/Tools/cases_generator/tier2_abstract_generator.py @@ -58,9 +58,8 @@ def declare_variables(uop: Uop, out: CWriter, skip_inputs: bool) -> None: out.emit(f"if({var.name}) {{goto error;}}\n") else: out.emit(f"{type_name(var)}{var.name};\n") - has_type_prop = any(output.type_prop is not None for output in uop.stack.outputs) for var in uop.stack.outputs: - if var.peek and not has_type_prop: + if var.peek: continue if var.name not in variables: variables.add(var.name) @@ -110,18 +109,15 @@ def write_uop( skip_inputs: bool, ) -> None: try: - has_type_prop = any( - output.type_prop is not None for output in (override or uop).stack.outputs - ) prototype = override if override else uop is_override = override is not None out.start_line() for var in reversed(prototype.stack.inputs): - if not skip_inputs or (has_type_prop and var.peek): + if not skip_inputs: out.emit(stack.pop(var)) if not prototype.properties.stores_sp: for i, var in enumerate(prototype.stack.outputs): - if not var.peek or is_override or has_type_prop: + if not var.peek or is_override: out.emit(stack.push(var)) if debug: args = [] @@ -129,7 +125,7 @@ def write_uop( if not var.peek or is_override: args.append(var.name) out.emit(f'DEBUG_PRINTF({", ".join(args)});\n') - if override or has_type_prop: + if override: for cache in uop.caches: if cache.name != "unused": if cache.size == 4: @@ -146,24 +142,6 @@ def write_uop( emit_tokens(out, override, stack, None, replacement_funcs) else: emit_default(out, uop) - # Type propagation - if has_type_prop: - out.emit("\n") - for output in (override or uop).stack.outputs: - if typ := output.type_prop: - typname, refinement = typ - refinement = refinement or "0" - # Special enum types, not corresponding to a specific PyTypeObject - if typname.isupper() and typname != "NULL": - print(typname) - out.emit(f"sym_set_type({output.name}, {typname}, {refinement});\n") - else: - out.emit(f"sym_set_pytype({output.name}, " - f"{'&' if typname != 'NULL' else ''}{typname}, {refinement});\n") - else: - # Silence compiler unused variable warnings. - if has_type_prop and output.name not in UNUSED: - out.emit(f"(void){output.name};\n") if prototype.properties.stores_sp: for i, var in enumerate(prototype.stack.outputs): From 54e2f64d2c72a57cb0e5093372dd3dea8247dc1e Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 7 Feb 2024 20:55:45 +0800 Subject: [PATCH 16/52] Add back SELF_OR_NULL :( --- Python/abstract_interp_cases.c.h | 24 ++++++++++++------- Python/optimizer_analysis.c | 11 +++++---- .../tier2_redundancy_eliminator_bytecodes.c | 17 +++++++++++-- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index 46bc87668ff1ed..372411c579c96e 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -762,16 +762,24 @@ } case _LOAD_ATTR: { + _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *self_or_null = sym_init_null(ctx); if(self_or_null) {goto error;} - attr = sym_init_unknown(ctx); - if (attr == NULL) goto error; + owner = stack_pointer[-1]; self_or_null = sym_init_unknown(ctx); - if (self_or_null == NULL) goto error; - stack_pointer[0] = attr; - if (oparg & 1) stack_pointer[1] = self_or_null; - stack_pointer += 1 + (oparg & 1); + if (self_or_null == NULL) { + goto error; + } + sym_set_type(self_or_null, SELF_OR_NULL, 0); + (void)owner; + attr = sym_init_unknown(ctx); + if (attr == NULL) { + goto error; + } + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = self_or_null; + stack_pointer += (oparg & 1); break; } @@ -1297,7 +1305,7 @@ assert(self_or_null != NULL); assert(args != NULL); if (!sym_matches_pytype(self_or_null, NULL, 0) && - !sym_is_unknown_type(self_or_null)) { + !sym_matches_type(self_or_null, SELF_OR_NULL, 0)) { // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in // VM args--; @@ -1308,7 +1316,7 @@ // Can determine statically, so we interleave the new locals // and make the current stack the new locals. // This also sets up for true call inlining. - if (!sym_is_unknown_type(self_or_null)) { + if (!sym_matches_type(self_or_null, SELF_OR_NULL, 0)) { localsplus_start = args; n_locals_already_filled = argcount; } diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 3afe2a66517be6..4752ec23c6147e 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -88,6 +88,12 @@ typedef enum { NULL_TYPE = 6, PYMETHOD_TYPE = 7, GUARD_DORV_VALUES_TYPE = 8, + // This is a non-ideal fix. Once all _LOAD_ATTR is properly annotated + // with proper type information (at least, that `self` is present), this + // can be removed. Otherwise, for now, this is used to distinguish + // _LOAD_ATTR (self/null unknown) and + // _LOAD_ATTR (unknown, but type cannot be captured in our current type system). + SELF_OR_NULL = 9, // Represents something from LOAD_CONST which is truly constant. TRUE_CONST = 30, @@ -491,11 +497,6 @@ sym_matches_pytype(_Py_UOpsSymType *sym, PyTypeObject *typ, uint64_t refinement) return sym_matches_type(sym, pytype_to_type(typ), refinement); } -static inline bool -sym_is_unknown_type(_Py_UOpsSymType *sym) -{ - return sym->types == 0 || (sym->types == 1U << INVALID_TYPE); -} static uint64_t sym_type_get_refinement(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ) diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index 33ae4d1829e6cd..ad995a03fe3446 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -152,6 +152,19 @@ dummy_func(void) { top, unused[oparg-2], bottom)) { } + op(_LOAD_ATTR, (owner -- attr, self_or_null if (oparg & 1))) { + self_or_null = sym_init_unknown(ctx); + if (self_or_null == NULL) { + goto error; + } + sym_set_type(self_or_null, SELF_OR_NULL, 0); + (void)owner; + attr = sym_init_unknown(ctx); + if (attr == NULL) { + goto error; + } + } + op(_CHECK_FUNCTION_EXACT_ARGS, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { sym_set_pytype(callable, &PyFunction_Type, func_version); (void)self_or_null; @@ -174,7 +187,7 @@ dummy_func(void) { assert(self_or_null != NULL); assert(args != NULL); if (!sym_matches_pytype(self_or_null, NULL, 0) && - !sym_is_unknown_type(self_or_null)) { + !sym_matches_type(self_or_null, SELF_OR_NULL, 0)) { // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in // VM args--; @@ -186,7 +199,7 @@ dummy_func(void) { // Can determine statically, so we interleave the new locals // and make the current stack the new locals. // This also sets up for true call inlining. - if (!sym_is_unknown_type(self_or_null)) { + if (!sym_matches_type(self_or_null, SELF_OR_NULL, 0)) { localsplus_start = args; n_locals_already_filled = argcount; } From dcddb2dea08c31721fa6dc16a5f195a672d847d6 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 7 Feb 2024 21:10:55 +0800 Subject: [PATCH 17/52] remove broken tests --- Lib/test/test_generated_cases.py | 48 -------------------------------- 1 file changed, 48 deletions(-) diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index a294c064ae6fdd..c33ec19bc80156 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -909,54 +909,6 @@ def test_no_overridden_case(self): """ self.run_cases_test(input, input2, output) - def test_no_overridden_case_type_prop(self): - input = """ - pure op(OP, (arg1 -- out: &PYLONG_TYPE)) { - spam(); - } - """ - input2 = """ - pure op(OTHER, (arg1 -- out)) { - spam(); - } - """ - output = """ - case OP: { - _Py_UOpsSymType *out; - out = sym_init_unknown(ctx); - if (out == NULL) goto error; - - sym_set_type(out, PYLONG_TYPE, 0); - stack_pointer[0] = out; - stack_pointer += 1; - break; - } - """ - self.run_cases_test(input, input2, output) - - def test_overridden_case_type_prop(self): - input = """ - pure op(OP, (arg1 -- out: &PYLONG_TYPE)) { - spam(); - } - """ - input2 = """ - pure op(OP, (arg1 -- out: &PYFLOAT_TYPE)) { - spam(); - } - """ - output = """ - case OP: { - _Py_UOpsSymType *arg1; - _Py_UOpsSymType *out; - arg1 = stack_pointer[-1]; - spam(); - sym_set_type(out, PYFLOAT_TYPE, 0); - stack_pointer[-1] = out; - break; - } - """ - self.run_cases_test(input, input2, output) if __name__ == "__main__": unittest.main() From 6e5ed12a784efafb86910c9abdd9def2b0828235 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 8 Feb 2024 19:52:54 +0800 Subject: [PATCH 18/52] address most reviews (except LOAD_ATTR todo) --- Include/internal/pycore_optimizer.h | 2 - Lib/test/test_capi/test_mem.py | 5 - Python/abstract_interp_cases.c.h | 79 +++++------ Python/optimizer.c | 10 +- Python/optimizer_analysis.c | 127 +++--------------- .../tier2_redundancy_eliminator_bytecodes.c | 40 +++--- .../tier2_abstract_generator.py | 6 +- 7 files changed, 86 insertions(+), 183 deletions(-) diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index a8ee8f29a73b22..663c01dcce02fa 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -12,8 +12,6 @@ extern "C" { // This is the length of the trace we project initially. #define UOP_MAX_TRACE_LENGTH 512 -// This the above + additional working space we need. -#define UOP_MAX_TRACE_WORKING_LENGTH (UOP_MAX_TRACE_LENGTH * 2) #define TRACE_STACK_SIZE 5 diff --git a/Lib/test/test_capi/test_mem.py b/Lib/test/test_capi/test_mem.py index 0aad2cc46d5afa..04f17a9ec9e72a 100644 --- a/Lib/test/test_capi/test_mem.py +++ b/Lib/test/test_capi/test_mem.py @@ -118,9 +118,6 @@ def test_pyobject_freed_is_freed(self): def test_set_nomemory(self): code = """if 1: import _testcapi - import _testinternalcapi - old_opt = _testinternalcapi.get_optimizer() - _testinternalcapi.set_optimizer(None) class C(): pass @@ -144,8 +141,6 @@ class C(): pass print('MemoryError', outer_cnt, j) _testcapi.remove_mem_hooks() break - - _testinternalcapi.set_optimizer(old_opt) """ rc, out, err = assert_python_ok('-c', code) lines = out.splitlines() diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index 372411c579c96e..0ed4a47931cb0d 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -178,12 +178,12 @@ _Py_UOpsSymType *left; right = stack_pointer[-1]; left = stack_pointer[-2]; - if (sym_matches_pytype(left, &PyLong_Type, 0) && - sym_matches_pytype(right, &PyLong_Type, 0)) { + if (sym_matches_pytype(left, &PyLong_Type) && + sym_matches_pytype(right, &PyLong_Type)) { REPLACE_OP(_NOP, 0, 0); } - sym_set_pytype(left, &PyLong_Type, 0); - sym_set_pytype(right, &PyLong_Type, 0); + sym_set_pytype(left, &PyLong_Type); + sym_set_pytype(right, &PyLong_Type); break; } @@ -205,7 +205,7 @@ // TODO constant propagation (void)left; (void)right; - res = sym_init_known_pytype(ctx, &PyLong_Type, 0); + res = sym_init_known_pytype(ctx, &PyLong_Type); if (res == NULL) { goto error; } @@ -228,12 +228,12 @@ _Py_UOpsSymType *left; right = stack_pointer[-1]; left = stack_pointer[-2]; - if (sym_matches_pytype(left, &PyFloat_Type, 0) && - sym_matches_pytype(right, &PyFloat_Type, 0)) { + if (sym_matches_pytype(left, &PyFloat_Type) && + sym_matches_pytype(right, &PyFloat_Type)) { REPLACE_OP(_NOP, 0 ,0); } - sym_set_pytype(left, &PyFloat_Type, 0); - sym_set_pytype(right, &PyFloat_Type, 0); + sym_set_pytype(left, &PyFloat_Type); + sym_set_pytype(right, &PyFloat_Type); break; } @@ -573,11 +573,11 @@ case _LOAD_GLOBAL: { _Py_UOpsSymType *res; - _Py_UOpsSymType *null = sym_init_null(ctx); + _Py_UOpsSymType *null = NULL; if(null) {goto error;} res = sym_init_unknown(ctx); if (res == NULL) goto error; - null = sym_init_unknown(ctx); + null = sym_init_null(ctx); if (null == NULL) goto error; stack_pointer[0] = res; if (oparg & 1) stack_pointer[1] = null; @@ -595,11 +595,11 @@ case _LOAD_GLOBAL_MODULE: { _Py_UOpsSymType *res; - _Py_UOpsSymType *null = sym_init_null(ctx); + _Py_UOpsSymType *null = NULL; if(null) {goto error;} res = sym_init_unknown(ctx); if (res == NULL) goto error; - null = sym_init_unknown(ctx); + null = sym_init_null(ctx); if (null == NULL) goto error; stack_pointer[0] = res; if (oparg & 1) stack_pointer[1] = null; @@ -609,11 +609,11 @@ case _LOAD_GLOBAL_BUILTINS: { _Py_UOpsSymType *res; - _Py_UOpsSymType *null = sym_init_null(ctx); + _Py_UOpsSymType *null = NULL; if(null) {goto error;} res = sym_init_unknown(ctx); if (res == NULL) goto error; - null = sym_init_unknown(ctx); + null = sym_init_null(ctx); if (null == NULL) goto error; stack_pointer[0] = res; if (oparg & 1) stack_pointer[1] = null; @@ -764,14 +764,14 @@ case _LOAD_ATTR: { _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; - _Py_UOpsSymType *self_or_null = sym_init_null(ctx); + _Py_UOpsSymType *self_or_null = NULL; if(self_or_null) {goto error;} owner = stack_pointer[-1]; self_or_null = sym_init_unknown(ctx); if (self_or_null == NULL) { goto error; } - sym_set_type(self_or_null, SELF_OR_NULL, 0); + sym_set_type(self_or_null, SELF_OR_NULL); (void)owner; attr = sym_init_unknown(ctx); if (attr == NULL) { @@ -793,11 +793,11 @@ case _LOAD_ATTR_INSTANCE_VALUE: { _Py_UOpsSymType *attr; - _Py_UOpsSymType *null = sym_init_null(ctx); + _Py_UOpsSymType *null = NULL; if(null) {goto error;} attr = sym_init_unknown(ctx); if (attr == NULL) goto error; - null = sym_init_unknown(ctx); + null = sym_init_null(ctx); if (null == NULL) goto error; stack_pointer[0] = attr; if (oparg & 1) stack_pointer[1] = null; @@ -811,11 +811,11 @@ case _LOAD_ATTR_MODULE: { _Py_UOpsSymType *attr; - _Py_UOpsSymType *null = sym_init_null(ctx); + _Py_UOpsSymType *null = NULL; if(null) {goto error;} attr = sym_init_unknown(ctx); if (attr == NULL) goto error; - null = sym_init_unknown(ctx); + null = sym_init_null(ctx); if (null == NULL) goto error; stack_pointer[0] = attr; if (oparg & 1) stack_pointer[1] = null; @@ -829,11 +829,11 @@ case _LOAD_ATTR_WITH_HINT: { _Py_UOpsSymType *attr; - _Py_UOpsSymType *null = sym_init_null(ctx); + _Py_UOpsSymType *null = NULL; if(null) {goto error;} attr = sym_init_unknown(ctx); if (attr == NULL) goto error; - null = sym_init_unknown(ctx); + null = sym_init_null(ctx); if (null == NULL) goto error; stack_pointer[0] = attr; if (oparg & 1) stack_pointer[1] = null; @@ -843,11 +843,11 @@ case _LOAD_ATTR_SLOT: { _Py_UOpsSymType *attr; - _Py_UOpsSymType *null = sym_init_null(ctx); + _Py_UOpsSymType *null = NULL; if(null) {goto error;} attr = sym_init_unknown(ctx); if (attr == NULL) goto error; - null = sym_init_unknown(ctx); + null = sym_init_null(ctx); if (null == NULL) goto error; stack_pointer[0] = attr; if (oparg & 1) stack_pointer[1] = null; @@ -861,11 +861,11 @@ case _LOAD_ATTR_CLASS: { _Py_UOpsSymType *attr; - _Py_UOpsSymType *null = sym_init_null(ctx); + _Py_UOpsSymType *null = NULL; if(null) {goto error;} attr = sym_init_unknown(ctx); if (attr == NULL) goto error; - null = sym_init_unknown(ctx); + null = sym_init_null(ctx); if (null == NULL) goto error; stack_pointer[0] = attr; if (oparg & 1) stack_pointer[1] = null; @@ -1110,7 +1110,7 @@ _Py_UOpsSymType *iter; _Py_UOpsSymType *next; iter = stack_pointer[-1]; - next = sym_init_known_pytype(ctx, &PyLong_Type, 0); + next = sym_init_known_pytype(ctx, &PyLong_Type); if (next == NULL) { goto error; } @@ -1180,7 +1180,7 @@ case _LOAD_ATTR_METHOD_WITH_VALUES: { _Py_UOpsSymType *attr; - _Py_UOpsSymType *self = sym_init_null(ctx); + _Py_UOpsSymType *self = NULL; if(self) {goto error;} attr = sym_init_unknown(ctx); if (attr == NULL) goto error; @@ -1194,7 +1194,7 @@ case _LOAD_ATTR_METHOD_NO_DICT: { _Py_UOpsSymType *attr; - _Py_UOpsSymType *self = sym_init_null(ctx); + _Py_UOpsSymType *self = NULL; if(self) {goto error;} attr = sym_init_unknown(ctx); if (attr == NULL) goto error; @@ -1230,7 +1230,7 @@ case _LOAD_ATTR_METHOD_LAZY_DICT: { _Py_UOpsSymType *attr; - _Py_UOpsSymType *self = sym_init_null(ctx); + _Py_UOpsSymType *self = NULL; if(self) {goto error;} attr = sym_init_unknown(ctx); if (attr == NULL) goto error; @@ -1251,8 +1251,8 @@ _Py_UOpsSymType *callable; null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - sym_set_pytype(null, NULL, 0); - sym_set_pytype(callable, &PyMethod_Type, 0); + sym_set_pytype(null, NULL); + sym_set_pytype(callable, &PyMethod_Type); break; } @@ -1279,8 +1279,9 @@ self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; uint32_t func_version = (uint32_t)inst->operand; - sym_set_pytype(callable, &PyFunction_Type, func_version); + sym_set_pytype(callable, &PyFunction_Type); (void)self_or_null; + (void)func_version; break; } @@ -1297,15 +1298,17 @@ self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; int argcount = oparg; - PyFunctionObject *func = extract_func_from_sym(callable); + (void)callable; + assert((inst + 2)->opcode == _PUSH_FRAME); + PyFunctionObject *func = (PyFunctionObject *)(inst + 2)->operand; if (func == NULL) { goto error; } PyCodeObject *co = (PyCodeObject *)func->func_code; assert(self_or_null != NULL); assert(args != NULL); - if (!sym_matches_pytype(self_or_null, NULL, 0) && - !sym_matches_type(self_or_null, SELF_OR_NULL, 0)) { + if (!sym_matches_pytype(self_or_null, NULL) && + !sym_matches_type(self_or_null, SELF_OR_NULL)) { // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in // VM args--; @@ -1316,7 +1319,7 @@ // Can determine statically, so we interleave the new locals // and make the current stack the new locals. // This also sets up for true call inlining. - if (!sym_matches_type(self_or_null, SELF_OR_NULL, 0)) { + if (!sym_matches_type(self_or_null, SELF_OR_NULL)) { localsplus_start = args; n_locals_already_filled = argcount; } diff --git a/Python/optimizer.c b/Python/optimizer.c index 8a53393128d2d8..e3cff36adab920 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -718,7 +718,7 @@ compute_used(_PyUOpInstruction *buffer, uint32_t *used) { int count = 0; SET_BIT(used, 0); - for (int i = 0; i < UOP_MAX_TRACE_WORKING_LENGTH; i++) { + for (int i = 0; i < UOP_MAX_TRACE_LENGTH; i++) { if (!BIT_IS_SET(used, i)) { continue; } @@ -750,7 +750,7 @@ compute_used(_PyUOpInstruction *buffer, uint32_t *used) static _PyExecutorObject * make_executor_from_uops(_PyUOpInstruction *buffer, _PyBloomFilter *dependencies) { - uint32_t used[(UOP_MAX_TRACE_WORKING_LENGTH + 31)/32] = { 0 }; + uint32_t used[(UOP_MAX_TRACE_LENGTH + 31)/32] = { 0 }; int length = compute_used(buffer, used); _PyExecutorObject *executor = PyObject_NewVar(_PyExecutorObject, &_PyUOpExecutor_Type, length); if (executor == NULL) { @@ -758,7 +758,7 @@ make_executor_from_uops(_PyUOpInstruction *buffer, _PyBloomFilter *dependencies) } int dest = length - 1; /* Scan backwards, so that we see the destinations of jumps before the jumps themselves. */ - for (int i = UOP_MAX_TRACE_WORKING_LENGTH-1; i >= 0; i--) { + for (int i = UOP_MAX_TRACE_LENGTH-1; i >= 0; i--) { if (!BIT_IS_SET(used, i)) { continue; } @@ -817,7 +817,7 @@ uop_optimize( { _PyBloomFilter dependencies; _Py_BloomFilter_Init(&dependencies); - _PyUOpInstruction buffer[UOP_MAX_TRACE_WORKING_LENGTH]; + _PyUOpInstruction buffer[UOP_MAX_TRACE_LENGTH]; int err = translate_bytecode_to_trace(frame, instr, buffer, UOP_MAX_TRACE_LENGTH, &dependencies); if (err <= 0) { // Error or nothing translated @@ -825,7 +825,7 @@ uop_optimize( } OPT_STAT_INC(traces_created); err = _Py_uop_analyze_and_optimize(frame, buffer, - UOP_MAX_TRACE_WORKING_LENGTH, curr_stackentries, &dependencies); + UOP_MAX_TRACE_LENGTH, curr_stackentries, &dependencies); if (err <= 0) { return err; } diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 4752ec23c6147e..e016eb34ce731a 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -38,7 +38,7 @@ #define OVERALLOCATE_FACTOR 5 -#define TY_ARENA_SIZE (UOP_MAX_TRACE_WORKING_LENGTH * OVERALLOCATE_FACTOR) +#define TY_ARENA_SIZE (UOP_MAX_TRACE_LENGTH * OVERALLOCATE_FACTOR) // Need extras for root frame and for overflow frame (see TRACE_STACK_PUSH()) #define MAX_ABSTRACT_FRAME_DEPTH (TRACE_STACK_SIZE + 2) @@ -102,20 +102,9 @@ typedef enum { #define MAX_TYPE_WITH_REFINEMENT PYFUNCTION_TYPE_VERSION_TYPE -static const uint32_t IMMUTABLES = - ( - 1 << NULL_TYPE | - 1 << PYLONG_TYPE | - 1 << PYFLOAT_TYPE | - 1 << PYUNICODE_TYPE | - 1 << TRUE_CONST - ); - typedef struct { // bitmask of types uint32_t types; - // refinement data for the types - uint64_t refinement[MAX_TYPE_WITH_REFINEMENT + 1]; // constant propagated value (might be NULL) PyObject *const_val; } _Py_UOpsSymType; @@ -275,30 +264,6 @@ abstractcontext_init( } -static inline bool -sym_is_type(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ); -static inline uint64_t -sym_type_get_refinement(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ); - -static inline PyFunctionObject * -extract_func_from_sym(_Py_UOpsSymType *callable_sym) -{ - assert(callable_sym != NULL); - if (!sym_is_type(callable_sym, PYFUNCTION_TYPE_VERSION_TYPE)) { - DPRINTF(1, "error: _PUSH_FRAME not function type\n"); - return NULL; - } - uint64_t func_version = sym_type_get_refinement(callable_sym, PYFUNCTION_TYPE_VERSION_TYPE); - PyFunctionObject *func = _PyFunction_LookupByVersion((uint32_t)func_version); - if (func == NULL) { - OPT_STAT_INC(optimizer_failure_reason_null_function); - DPRINTF(1, "error: _PUSH_FRAME cannot find func version\n"); - return NULL; - } - return func; -} - - static int ctx_frame_pop( _Py_UOpsAbstractInterpContext *ctx @@ -341,31 +306,9 @@ _Py_UOpsSymType_New(_Py_UOpsAbstractInterpContext *ctx, static void -sym_set_type(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ, uint64_t refinement) +sym_set_type(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ) { sym->types |= 1 << typ; - if (typ <= MAX_TYPE_WITH_REFINEMENT) { - sym->refinement[typ] = refinement; - } -} - -// We need to clear the type information on every escaping/impure instruction. -// Consider the following code -/* -foo.attr -bar() # opaque call -foo.attr -*/ -// We can't propagate the type information of foo.attr over across bar -// (at least, not without re-installing guards). `bar()` may call random code -// that invalidates foo's type version tag. -static void -sym_copy_immutable_type_info(_Py_UOpsSymType *from_sym, _Py_UOpsSymType *to_sym) -{ - to_sym->types = (from_sym->types & IMMUTABLES); - if (to_sym->types) { - Py_XSETREF(to_sym->const_val, Py_XNewRef(from_sym->const_val)); - } } @@ -395,10 +338,10 @@ pytype_to_type(PyTypeObject *tp) } static void -sym_set_pytype(_Py_UOpsSymType *sym, PyTypeObject *tp, uint64_t refinement) +sym_set_pytype(_Py_UOpsSymType *sym, PyTypeObject *tp) { assert(tp == NULL || PyType_Check(tp)); - sym_set_type(sym, pytype_to_type(tp), refinement); + sym_set_type(sym, pytype_to_type(tp)); } static void @@ -407,14 +350,13 @@ sym_set_type_from_const(_Py_UOpsSymType *sym, PyObject *obj) PyTypeObject *tp = Py_TYPE(obj); if (tp->tp_version_tag != 0) { - sym_set_type(sym, GUARD_TYPE_VERSION_TYPE, tp->tp_version_tag); + sym_set_type(sym, GUARD_TYPE_VERSION_TYPE); } if (tp == &PyFunction_Type) { - sym_set_type(sym, PYFUNCTION_TYPE_VERSION_TYPE, - ((PyFunctionObject *)(obj))->func_version); + sym_set_type(sym, PYFUNCTION_TYPE_VERSION_TYPE); } else { - sym_set_pytype(sym, tp, 0); + sym_set_pytype(sym, tp); } } @@ -427,13 +369,13 @@ sym_init_unknown(_Py_UOpsAbstractInterpContext *ctx) static inline _Py_UOpsSymType* sym_init_known_pytype(_Py_UOpsAbstractInterpContext *ctx, - PyTypeObject *typ, uint64_t refinement) + PyTypeObject *typ) { _Py_UOpsSymType *res = _Py_UOpsSymType_New(ctx,NULL); if (res == NULL) { return NULL; } - sym_set_pytype(res, typ, refinement); + sym_set_pytype(res, typ); return res; } @@ -450,7 +392,7 @@ sym_init_const(_Py_UOpsAbstractInterpContext *ctx, PyObject *const_val) return NULL; } sym_set_type_from_const(temp, const_val); - sym_set_type(temp, TRUE_CONST, 0); + sym_set_type(temp, TRUE_CONST); return temp; } @@ -464,7 +406,7 @@ sym_init_null(_Py_UOpsAbstractInterpContext *ctx) if (null_sym == NULL) { return NULL; } - sym_set_type(null_sym, NULL_TYPE, 0); + sym_set_type(null_sym, NULL_TYPE); ctx->frequent_syms.push_nulL_sym = null_sym; return null_sym; } @@ -479,31 +421,19 @@ sym_is_type(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ) } static inline bool -sym_matches_type(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ, uint64_t refinement) +sym_matches_type(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ) { if (!sym_is_type(sym, typ)) { return false; } - if (typ <= MAX_TYPE_WITH_REFINEMENT) { - return sym->refinement[typ] == refinement; - } return true; } static inline bool -sym_matches_pytype(_Py_UOpsSymType *sym, PyTypeObject *typ, uint64_t refinement) +sym_matches_pytype(_Py_UOpsSymType *sym, PyTypeObject *typ) { assert(typ == NULL || PyType_Check(typ)); - return sym_matches_type(sym, pytype_to_type(typ), refinement); -} - - -static uint64_t -sym_type_get_refinement(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ) -{ - assert(sym_is_type(sym, typ)); - assert(typ <= MAX_TYPE_WITH_REFINEMENT); - return sym->refinement[typ]; + return sym_matches_type(sym, pytype_to_type(typ)); } @@ -531,15 +461,6 @@ op_is_data_movement_only(uint32_t opcode) { } -static int -clear_locals_type_info(_Py_UOpsAbstractInterpContext *ctx) { - int locals_entries = ctx->frame->locals_len; - for (int i = 0; i < locals_entries; i++) { - sym_copy_immutable_type_info(ctx->frame->locals[i], ctx->frame->locals[i]); - } - return 0; -} - static inline int emit_i(uops_emitter *emitter, _PyUOpInstruction inst) @@ -837,31 +758,13 @@ uop_redundancy_eliminator( _PyUOpInstruction *curr = NULL; _PyUOpInstruction *end = NULL; int status = 0; - bool needs_clear_locals = true; int res = 0; curr = trace; end = trace + trace_len; - needs_clear_locals = true; ; while (curr < end && !op_is_end(curr->opcode)) { - if (!(_PyUop_Flags[curr->opcode] & HAS_PURE_FLAG) && - !op_is_bookkeeping(curr->opcode) && - !op_is_data_movement_only(curr->opcode) && - !(_PyUop_Flags[curr->opcode] & HAS_PASSTHROUGH_FLAG)) { - DPRINTF(3, "Impure %s\n", _PyOpcode_uop_name[curr->opcode]); - if (needs_clear_locals) { - if (clear_locals_type_info(&ctx) < 0) { - goto error; - } - } - needs_clear_locals = false; - } - else { - needs_clear_locals = true; - } - status = uop_abstract_interpret_single_inst( curr, end, &ctx ); @@ -984,7 +887,7 @@ _Py_uop_analyze_and_optimize( ) { OPT_STAT_INC(optimizer_attempts); - _PyUOpInstruction temp_writebuffer[UOP_MAX_TRACE_WORKING_LENGTH]; + _PyUOpInstruction temp_writebuffer[UOP_MAX_TRACE_LENGTH]; int err = remove_globals(frame, buffer, buffer_size, dependencies); if (err <= 0) { diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index ad995a03fe3446..9c820a006e01fc 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -66,21 +66,21 @@ dummy_func(void) { } op(_GUARD_BOTH_INT, (left, right -- left, right)) { - if (sym_matches_pytype(left, &PyLong_Type, 0) && - sym_matches_pytype(right, &PyLong_Type, 0)) { + if (sym_matches_pytype(left, &PyLong_Type) && + sym_matches_pytype(right, &PyLong_Type)) { REPLACE_OP(_NOP, 0, 0); } - sym_set_pytype(left, &PyLong_Type, 0); - sym_set_pytype(right, &PyLong_Type, 0); + sym_set_pytype(left, &PyLong_Type); + sym_set_pytype(right, &PyLong_Type); } op(_GUARD_BOTH_FLOAT, (left, right -- left, right)) { - if (sym_matches_pytype(left, &PyFloat_Type, 0) && - sym_matches_pytype(right, &PyFloat_Type, 0)) { + if (sym_matches_pytype(left, &PyFloat_Type) && + sym_matches_pytype(right, &PyFloat_Type)) { REPLACE_OP(_NOP, 0 ,0); } - sym_set_pytype(left, &PyFloat_Type, 0); - sym_set_pytype(right, &PyFloat_Type, 0); + sym_set_pytype(left, &PyFloat_Type); + sym_set_pytype(right, &PyFloat_Type); } @@ -88,7 +88,7 @@ dummy_func(void) { // TODO constant propagation (void)left; (void)right; - res = sym_init_known_pytype(ctx, &PyLong_Type, 0); + res = sym_init_known_pytype(ctx, &PyLong_Type); if (res == NULL) { goto error; } @@ -157,7 +157,7 @@ dummy_func(void) { if (self_or_null == NULL) { goto error; } - sym_set_type(self_or_null, SELF_OR_NULL, 0); + sym_set_type(self_or_null, SELF_OR_NULL); (void)owner; attr = sym_init_unknown(ctx); if (attr == NULL) { @@ -166,19 +166,23 @@ dummy_func(void) { } op(_CHECK_FUNCTION_EXACT_ARGS, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { - sym_set_pytype(callable, &PyFunction_Type, func_version); + sym_set_pytype(callable, &PyFunction_Type); (void)self_or_null; + (void)func_version; } op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- callable, null, unused[oparg])) { - sym_set_pytype(null, NULL, 0); - sym_set_pytype(callable, &PyMethod_Type, 0); + sym_set_pytype(null, NULL); + sym_set_pytype(callable, &PyMethod_Type); } op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null, args[oparg] -- new_frame: _Py_UOpsAbstractFrame *)) { int argcount = oparg; - PyFunctionObject *func = extract_func_from_sym(callable); + (void)callable; + + assert((inst + 2)->opcode == _PUSH_FRAME); + PyFunctionObject *func = (PyFunctionObject *)(inst + 2)->operand; if (func == NULL) { goto error; } @@ -186,8 +190,8 @@ dummy_func(void) { assert(self_or_null != NULL); assert(args != NULL); - if (!sym_matches_pytype(self_or_null, NULL, 0) && - !sym_matches_type(self_or_null, SELF_OR_NULL, 0)) { + if (!sym_matches_pytype(self_or_null, NULL) && + !sym_matches_type(self_or_null, SELF_OR_NULL)) { // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in // VM args--; @@ -199,7 +203,7 @@ dummy_func(void) { // Can determine statically, so we interleave the new locals // and make the current stack the new locals. // This also sets up for true call inlining. - if (!sym_matches_type(self_or_null, SELF_OR_NULL, 0)) { + if (!sym_matches_type(self_or_null, SELF_OR_NULL)) { localsplus_start = args; n_locals_already_filled = argcount; } @@ -249,7 +253,7 @@ dummy_func(void) { } op(_ITER_NEXT_RANGE, (iter -- iter, next)) { - next = sym_init_known_pytype(ctx, &PyLong_Type, 0); + next = sym_init_known_pytype(ctx, &PyLong_Type); if (next == NULL) { goto error; } diff --git a/Tools/cases_generator/tier2_abstract_generator.py b/Tools/cases_generator/tier2_abstract_generator.py index 559b610b8ab5ca..092b76ee285469 100644 --- a/Tools/cases_generator/tier2_abstract_generator.py +++ b/Tools/cases_generator/tier2_abstract_generator.py @@ -54,7 +54,7 @@ def declare_variables(uop: Uop, out: CWriter, skip_inputs: bool) -> None: if var.name not in variables: variables.add(var.name) if var.condition: - out.emit(f"{type_name(var)}{var.name} = sym_init_null(ctx);\n") + out.emit(f"{type_name(var)}{var.name} = NULL;\n") out.emit(f"if({var.name}) {{goto error;}}\n") else: out.emit(f"{type_name(var)}{var.name};\n") @@ -64,7 +64,7 @@ def declare_variables(uop: Uop, out: CWriter, skip_inputs: bool) -> None: if var.name not in variables: variables.add(var.name) if var.condition: - out.emit(f"{type_name(var)}{var.name} = sym_init_null(ctx);\n") + out.emit(f"{type_name(var)}{var.name} = NULL;\n") out.emit(f"if({var.name}) {{goto error;}}\n") else: out.emit(f"{type_name(var)}{var.name};\n") @@ -93,7 +93,7 @@ def emit_default(out: CWriter, uop: Uop) -> None: out.emit(f"if ({var.name}[_i] == NULL) goto error;\n") out.emit("}\n") elif var.name == "null": - out.emit(f"{var.name} = sym_init_unknown(ctx);\n") + out.emit(f"{var.name} = sym_init_null(ctx);\n") out.emit(f"if ({var.name} == NULL) goto error;\n") else: out.emit(f"{var.name} = sym_init_unknown(ctx);\n") From a8b27fc46cd4ed2aede1fa3eba0325444d3a0496 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 8 Feb 2024 20:10:22 +0800 Subject: [PATCH 19/52] implement NOT_NULL for attributes --- Python/abstract_interp_cases.c.h | 117 ++++++++---------- Python/optimizer_analysis.c | 36 +++++- .../tier2_redundancy_eliminator_bytecodes.c | 42 +++++-- .../tier2_abstract_generator.py | 2 - 4 files changed, 112 insertions(+), 85 deletions(-) diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index 0ed4a47931cb0d..dafae2fe5f05fd 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -574,7 +574,6 @@ case _LOAD_GLOBAL: { _Py_UOpsSymType *res; _Py_UOpsSymType *null = NULL; - if(null) {goto error;} res = sym_init_unknown(ctx); if (res == NULL) goto error; null = sym_init_null(ctx); @@ -596,7 +595,6 @@ case _LOAD_GLOBAL_MODULE: { _Py_UOpsSymType *res; _Py_UOpsSymType *null = NULL; - if(null) {goto error;} res = sym_init_unknown(ctx); if (res == NULL) goto error; null = sym_init_null(ctx); @@ -610,7 +608,6 @@ case _LOAD_GLOBAL_BUILTINS: { _Py_UOpsSymType *res; _Py_UOpsSymType *null = NULL; - if(null) {goto error;} res = sym_init_unknown(ctx); if (res == NULL) goto error; null = sym_init_null(ctx); @@ -762,24 +759,15 @@ } case _LOAD_ATTR: { - _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *self_or_null = NULL; - if(self_or_null) {goto error;} - owner = stack_pointer[-1]; - self_or_null = sym_init_unknown(ctx); - if (self_or_null == NULL) { - goto error; - } - sym_set_type(self_or_null, SELF_OR_NULL); - (void)owner; attr = sym_init_unknown(ctx); - if (attr == NULL) { - goto error; - } - stack_pointer[-1] = attr; - if (oparg & 1) stack_pointer[0] = self_or_null; - stack_pointer += (oparg & 1); + if (attr == NULL) goto error; + self_or_null = sym_init_unknown(ctx); + if (self_or_null == NULL) goto error; + stack_pointer[0] = attr; + if (oparg & 1) stack_pointer[1] = self_or_null; + stack_pointer += 1 + (oparg & 1); break; } @@ -792,16 +780,17 @@ } case _LOAD_ATTR_INSTANCE_VALUE: { + _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *null = NULL; - if(null) {goto error;} - attr = sym_init_unknown(ctx); - if (attr == NULL) goto error; - null = sym_init_null(ctx); - if (null == NULL) goto error; - stack_pointer[0] = attr; - if (oparg & 1) stack_pointer[1] = null; - stack_pointer += 1 + (oparg & 1); + owner = stack_pointer[-1]; + uint16_t index = (uint16_t)inst->operand; + _LOAD_ATTR_NOT_NULL + (void)index; + (void)owner; + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += (oparg & 1); break; } @@ -810,16 +799,17 @@ } case _LOAD_ATTR_MODULE: { + _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *null = NULL; - if(null) {goto error;} - attr = sym_init_unknown(ctx); - if (attr == NULL) goto error; - null = sym_init_null(ctx); - if (null == NULL) goto error; - stack_pointer[0] = attr; - if (oparg & 1) stack_pointer[1] = null; - stack_pointer += 1 + (oparg & 1); + owner = stack_pointer[-1]; + uint16_t index = (uint16_t)inst->operand; + _LOAD_ATTR_NOT_NULL + (void)index; + (void)owner; + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += (oparg & 1); break; } @@ -828,30 +818,32 @@ } case _LOAD_ATTR_WITH_HINT: { + _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *null = NULL; - if(null) {goto error;} - attr = sym_init_unknown(ctx); - if (attr == NULL) goto error; - null = sym_init_null(ctx); - if (null == NULL) goto error; - stack_pointer[0] = attr; - if (oparg & 1) stack_pointer[1] = null; - stack_pointer += 1 + (oparg & 1); + owner = stack_pointer[-1]; + uint16_t hint = (uint16_t)inst->operand; + _LOAD_ATTR_NOT_NULL + (void)hint; + (void)owner; + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += (oparg & 1); break; } case _LOAD_ATTR_SLOT: { + _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *null = NULL; - if(null) {goto error;} - attr = sym_init_unknown(ctx); - if (attr == NULL) goto error; - null = sym_init_null(ctx); - if (null == NULL) goto error; - stack_pointer[0] = attr; - if (oparg & 1) stack_pointer[1] = null; - stack_pointer += 1 + (oparg & 1); + owner = stack_pointer[-1]; + uint16_t index = (uint16_t)inst->operand; + _LOAD_ATTR_NOT_NULL + (void)index; + (void)owner; + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += (oparg & 1); break; } @@ -860,16 +852,17 @@ } case _LOAD_ATTR_CLASS: { + _Py_UOpsSymType *owner; _Py_UOpsSymType *attr; _Py_UOpsSymType *null = NULL; - if(null) {goto error;} - attr = sym_init_unknown(ctx); - if (attr == NULL) goto error; - null = sym_init_null(ctx); - if (null == NULL) goto error; - stack_pointer[0] = attr; - if (oparg & 1) stack_pointer[1] = null; - stack_pointer += 1 + (oparg & 1); + owner = stack_pointer[-1]; + PyObject *descr = (PyObject *)inst->operand; + _LOAD_ATTR_NOT_NULL + (void)descr; + (void)owner; + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += (oparg & 1); break; } @@ -1181,7 +1174,6 @@ case _LOAD_ATTR_METHOD_WITH_VALUES: { _Py_UOpsSymType *attr; _Py_UOpsSymType *self = NULL; - if(self) {goto error;} attr = sym_init_unknown(ctx); if (attr == NULL) goto error; self = sym_init_unknown(ctx); @@ -1195,7 +1187,6 @@ case _LOAD_ATTR_METHOD_NO_DICT: { _Py_UOpsSymType *attr; _Py_UOpsSymType *self = NULL; - if(self) {goto error;} attr = sym_init_unknown(ctx); if (attr == NULL) goto error; self = sym_init_unknown(ctx); @@ -1231,7 +1222,6 @@ case _LOAD_ATTR_METHOD_LAZY_DICT: { _Py_UOpsSymType *attr; _Py_UOpsSymType *self = NULL; - if(self) {goto error;} attr = sym_init_unknown(ctx); if (attr == NULL) goto error; self = sym_init_unknown(ctx); @@ -1307,8 +1297,7 @@ PyCodeObject *co = (PyCodeObject *)func->func_code; assert(self_or_null != NULL); assert(args != NULL); - if (!sym_matches_pytype(self_or_null, NULL) && - !sym_matches_type(self_or_null, SELF_OR_NULL)) { + if (sym_matches_type(self_or_null, NOT_NULL)) { // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in // VM args--; @@ -1319,7 +1308,7 @@ // Can determine statically, so we interleave the new locals // and make the current stack the new locals. // This also sets up for true call inlining. - if (!sym_matches_type(self_or_null, SELF_OR_NULL)) { + if (!sym_is_unknown_type(self_or_null)) { localsplus_start = args; n_locals_already_filled = argcount; } diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index e016eb34ce731a..096ebbd8a86035 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -88,12 +88,7 @@ typedef enum { NULL_TYPE = 6, PYMETHOD_TYPE = 7, GUARD_DORV_VALUES_TYPE = 8, - // This is a non-ideal fix. Once all _LOAD_ATTR is properly annotated - // with proper type information (at least, that `self` is present), this - // can be removed. Otherwise, for now, this is used to distinguish - // _LOAD_ATTR (self/null unknown) and - // _LOAD_ATTR (unknown, but type cannot be captured in our current type system). - SELF_OR_NULL = 9, + NOT_NULL = 9, // Represents something from LOAD_CONST which is truly constant. TRUE_CONST = 30, @@ -367,6 +362,24 @@ sym_init_unknown(_Py_UOpsAbstractInterpContext *ctx) return _Py_UOpsSymType_New(ctx,NULL); } +static inline bool +sym_is_unknown_type(_Py_UOpsSymType *typ) +{ + return (typ->types == 0) || (typ->types == (1U << INVALID_TYPE)); +} + +static inline _Py_UOpsSymType* +sym_init_known_type(_Py_UOpsAbstractInterpContext *ctx, + _Py_UOpsSymExprTypeEnum typ) +{ + _Py_UOpsSymType *res = sym_init_unknown(ctx); + if (res == NULL) { + return NULL; + } + sym_set_type(res, typ); + return res; +} + static inline _Py_UOpsSymType* sym_init_known_pytype(_Py_UOpsAbstractInterpContext *ctx, PyTypeObject *typ) @@ -500,6 +513,17 @@ uop_abstract_interpret_single_inst( new_inst.oparg = arg; \ new_inst.operand = oper; +#define _LOAD_ATTR_NOT_NULL \ + do { \ + attr = sym_init_known_type(ctx, NOT_NULL); \ + if (attr == NULL) { \ + goto error; \ + } \ + null = sym_init_null(ctx); \ + if (null == NULL) { \ + goto error; \ + } \ + } while (0); int oparg = inst->oparg; uint32_t opcode = inst->opcode; diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index 9c820a006e01fc..e9bb25cff41b68 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -152,17 +152,34 @@ dummy_func(void) { top, unused[oparg-2], bottom)) { } - op(_LOAD_ATTR, (owner -- attr, self_or_null if (oparg & 1))) { - self_or_null = sym_init_unknown(ctx); - if (self_or_null == NULL) { - goto error; - } - sym_set_type(self_or_null, SELF_OR_NULL); + op(_LOAD_ATTR_INSTANCE_VALUE, (index/1, owner -- attr, null if (oparg & 1))) { + _LOAD_ATTR_NOT_NULL + (void)index; + (void)owner; + } + + op(_LOAD_ATTR_MODULE, (index/1, owner -- attr, null if (oparg & 1))) { + _LOAD_ATTR_NOT_NULL + (void)index; + (void)owner; + } + + op(_LOAD_ATTR_WITH_HINT, (hint/1, owner -- attr, null if (oparg & 1))) { + _LOAD_ATTR_NOT_NULL + (void)hint; + (void)owner; + } + + op(_LOAD_ATTR_SLOT, (index/1, owner -- attr, null if (oparg & 1))) { + _LOAD_ATTR_NOT_NULL + (void)index; + (void)owner; + } + + op(_LOAD_ATTR_CLASS, (descr/4, owner -- attr, null if (oparg & 1))) { + _LOAD_ATTR_NOT_NULL + (void)descr; (void)owner; - attr = sym_init_unknown(ctx); - if (attr == NULL) { - goto error; - } } op(_CHECK_FUNCTION_EXACT_ARGS, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { @@ -190,8 +207,7 @@ dummy_func(void) { assert(self_or_null != NULL); assert(args != NULL); - if (!sym_matches_pytype(self_or_null, NULL) && - !sym_matches_type(self_or_null, SELF_OR_NULL)) { + if (sym_matches_type(self_or_null, NOT_NULL)) { // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in // VM args--; @@ -203,7 +219,7 @@ dummy_func(void) { // Can determine statically, so we interleave the new locals // and make the current stack the new locals. // This also sets up for true call inlining. - if (!sym_matches_type(self_or_null, SELF_OR_NULL)) { + if (!sym_is_unknown_type(self_or_null)) { localsplus_start = args; n_locals_already_filled = argcount; } diff --git a/Tools/cases_generator/tier2_abstract_generator.py b/Tools/cases_generator/tier2_abstract_generator.py index 092b76ee285469..78037dbcc0ba84 100644 --- a/Tools/cases_generator/tier2_abstract_generator.py +++ b/Tools/cases_generator/tier2_abstract_generator.py @@ -55,7 +55,6 @@ def declare_variables(uop: Uop, out: CWriter, skip_inputs: bool) -> None: variables.add(var.name) if var.condition: out.emit(f"{type_name(var)}{var.name} = NULL;\n") - out.emit(f"if({var.name}) {{goto error;}}\n") else: out.emit(f"{type_name(var)}{var.name};\n") for var in uop.stack.outputs: @@ -65,7 +64,6 @@ def declare_variables(uop: Uop, out: CWriter, skip_inputs: bool) -> None: variables.add(var.name) if var.condition: out.emit(f"{type_name(var)}{var.name} = NULL;\n") - out.emit(f"if({var.name}) {{goto error;}}\n") else: out.emit(f"{type_name(var)}{var.name};\n") From e00ec6fb26038fc9714bff62e3076bf4618212c1 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 8 Feb 2024 20:11:33 +0800 Subject: [PATCH 20/52] revert function version cache size --- Include/internal/pycore_function.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/internal/pycore_function.h b/Include/internal/pycore_function.h index b3f88befb5c540..3f3da8a44b77e4 100644 --- a/Include/internal/pycore_function.h +++ b/Include/internal/pycore_function.h @@ -16,7 +16,7 @@ extern PyObject* _PyFunction_Vectorcall( #define FUNC_MAX_WATCHERS 8 -#define FUNC_VERSION_CACHE_SIZE (1<<14) /* Must be a power of 2 */ +#define FUNC_VERSION_CACHE_SIZE (1<<12) /* Must be a power of 2 */ struct _py_func_state { uint32_t next_version; // Borrowed references to function objects whose From b8f0af1f21ff22f96a75739336076ad5e38801d8 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 8 Feb 2024 21:49:47 +0800 Subject: [PATCH 21/52] remove unused stats --- Include/cpython/pystats.h | 3 --- Python/specialize.c | 6 ------ 2 files changed, 9 deletions(-) diff --git a/Include/cpython/pystats.h b/Include/cpython/pystats.h index 9f3ceb497e5fa6..0537c4702a0717 100644 --- a/Include/cpython/pystats.h +++ b/Include/cpython/pystats.h @@ -125,9 +125,6 @@ typedef struct _optimization_stats { uint64_t optimizer_failure_reason_null_function; uint64_t optimizer_failure_reason_no_memory; uint64_t optimizer_failure_reason_no_writebuffer; - uint64_t loop_body_duplication_attempts; - uint64_t loop_body_duplication_successes; - uint64_t loop_body_duplication_no_mem; } OptimizationStats; typedef struct _rare_event_stats { diff --git a/Python/specialize.c b/Python/specialize.c index e288db90d01105..1704262018854e 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -248,12 +248,6 @@ print_optimization_stats(FILE *out, OptimizationStats *stats) stats->optimizer_failure_reason_no_memory); fprintf(out, "Optimization optimizer failure no writebuffer left: %" PRIu64 "\n", stats->optimizer_failure_reason_no_writebuffer); - fprintf(out, "Optimization optimizer loop duplication attempts: %" PRIu64 "\n", - stats->loop_body_duplication_attempts); - fprintf(out, "Optimization optimizer loop duplication successes: %" PRIu64 "\n", - stats->loop_body_duplication_successes); - fprintf(out, "Optimization optimizer loop duplication no memory: %" PRIu64 "\n", - stats->loop_body_duplication_no_mem); const char* const* names; for (int i = 0; i < 512; i++) { From 9a9033f2f05e28a29a471d13739a7343125bad0d Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 8 Feb 2024 22:12:49 +0800 Subject: [PATCH 22/52] remove unused macro --- Python/optimizer_analysis.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 096ebbd8a86035..ff7b99c4b7fdb7 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -95,8 +95,6 @@ typedef enum { INVALID_TYPE = 31, } _Py_UOpsSymExprTypeEnum; -#define MAX_TYPE_WITH_REFINEMENT PYFUNCTION_TYPE_VERSION_TYPE - typedef struct { // bitmask of types uint32_t types; From 710f6092f3381e5b40e2674daf587b20b0e56c44 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 8 Feb 2024 22:14:42 +0800 Subject: [PATCH 23/52] remove unused types --- Python/optimizer_analysis.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index ff7b99c4b7fdb7..39c18709b43a0f 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -64,17 +64,11 @@ * `PYFLOAT_TYPE`: `Py_TYPE(val) == &PyFloat_Type` * `PYUNICODE_TYPE`: `Py_TYPE(val) == &PYUNICODE_TYPE` * `NULL_TYPE`: `val == NULL` -* `GUARD_TYPE_VERSION_TYPE`: `type->tp_version_tag == auxillary` -* `GUARD_DORV_VALUES_TYPE`: `_PyDictOrValues_IsValues(obj)` -* `GUARD_KEYS_VERSION_TYPE`: `owner_heap_type->ht_cached_keys->dk_version == auxillary` * `PYMETHOD_TYPE`: `Py_TYPE(val) == &PyMethod_Type` * `PYFUNCTION_TYPE_VERSION_TYPE`: - `PyFunction_Check(callable) && func->func_version == auxillary && code->co_argcount == oparg + (self_or_null != NULL)` + `PyFunction_Check(callable) && code->co_argcount == oparg + (self_or_null != NULL)` */ typedef enum { - // Types with refinement info - GUARD_KEYS_VERSION_TYPE = 0, - GUARD_TYPE_VERSION_TYPE = 1, // You might think this actually needs to encode oparg // info as well, see _CHECK_FUNCTION_EXACT_ARGS. // However, since oparg is tied to code object is tied to function version, @@ -87,7 +81,6 @@ typedef enum { PYUNICODE_TYPE = 5, NULL_TYPE = 6, PYMETHOD_TYPE = 7, - GUARD_DORV_VALUES_TYPE = 8, NOT_NULL = 9, // Represents something from LOAD_CONST which is truly constant. @@ -342,9 +335,6 @@ sym_set_type_from_const(_Py_UOpsSymType *sym, PyObject *obj) { PyTypeObject *tp = Py_TYPE(obj); - if (tp->tp_version_tag != 0) { - sym_set_type(sym, GUARD_TYPE_VERSION_TYPE); - } if (tp == &PyFunction_Type) { sym_set_type(sym, PYFUNCTION_TYPE_VERSION_TYPE); } From eaeb29365c9399c9c52defd1b25e72ef09cbdd82 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 8 Feb 2024 22:21:57 +0800 Subject: [PATCH 24/52] remove unused import --- Lib/test/test_capi/test_opt.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 8e100a35047dbb..9b47e28eb01c69 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -6,8 +6,6 @@ import _testinternalcapi -from test.support.script_helper import assert_python_ok -from test import support @contextlib.contextmanager def temporary_optimizer(opt): From 0bb9539d324bc6511a0934f58bde65093d904c40 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 8 Feb 2024 23:40:04 +0800 Subject: [PATCH 25/52] rename file to tier2_redundancy_eliminator --- .gitattributes | 2 +- Include/internal/pycore_optimizer.h | 2 -- Lib/test/test_capi/test_opt.py | 1 - Makefile.pre.in | 6 ++-- Python/optimizer.c | 12 ++++--- Python/optimizer_analysis.c | 3 +- Python/pylifecycle.c | 2 +- .../tier2_redundancy_eliminator_bytecodes.c | 33 ++++++++----------- ... => tier2_redundancy_eliminator_cases.c.h} | 33 ++++++++----------- Tools/c-analyzer/cpython/_parser.py | 2 +- Tools/cases_generator/README.md | 2 +- .../tier2_abstract_generator.py | 4 +-- 12 files changed, 45 insertions(+), 57 deletions(-) rename Python/{abstract_interp_cases.c.h => tier2_redundancy_eliminator_cases.c.h} (98%) diff --git a/.gitattributes b/.gitattributes index 22afffb05abb20..07d877027b09f6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -94,7 +94,7 @@ Programs/test_frozenmain.h generated Python/Python-ast.c generated Python/executor_cases.c.h generated Python/generated_cases.c.h generated -Python/abstract_interp_cases.c.h generated +Python/tier2_redundancy_eliminator_bytecodes.c.h generated Python/opcode_targets.h generated Python/stdlib_module_names.h generated Tools/peg_generator/pegen/grammar_parser.py generated diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 663c01dcce02fa..eee71c700d4904 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -19,8 +19,6 @@ int _Py_uop_analyze_and_optimize(_PyInterpreterFrame *frame, _PyUOpInstruction *trace, int trace_len, int curr_stackentries, _PyBloomFilter *dependencies); - - extern PyTypeObject _PyCounterExecutor_Type; extern PyTypeObject _PyCounterOptimizer_Type; extern PyTypeObject _PyDefaultOptimizer_Type; diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 9b47e28eb01c69..d54eb1d713e62c 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -543,7 +543,6 @@ def testfunc(n): class TestUopsOptimization(unittest.TestCase): - def test_int_type_propagation(self): def testfunc(loops): num = 0 diff --git a/Makefile.pre.in b/Makefile.pre.in index 1c0e49e39e88b2..433b401248ca40 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1606,7 +1606,7 @@ regen-cases: $(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/tier2_abstract_generator.py \ - -o $(srcdir)/Python/abstract_interp_cases.c.h.new \ + -o $(srcdir)/Python/tier2_redundancy_eliminator_cases.c.h.new \ $(srcdir)/Python/tier2_redundancy_eliminator_bytecodes.c \ $(srcdir)/Python/bytecodes.c $(PYTHON_FOR_REGEN) $(srcdir)/Tools/cases_generator/opcode_metadata_generator.py \ @@ -1620,7 +1620,7 @@ regen-cases: $(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)/Python/tier2_redundancy_eliminator_cases.c.h $(srcdir)/Python/tier2_redundancy_eliminator_cases.c.h.new $(UPDATE_FILE) $(srcdir)/Lib/_opcode_metadata.py $(srcdir)/Lib/_opcode_metadata.py.new Python/compile.o: $(srcdir)/Include/internal/pycore_opcode_metadata.h @@ -1643,7 +1643,7 @@ Python/optimizer.o: \ Python/optimizer_analysis.o: \ $(srcdir)/Include/internal/pycore_opcode_metadata.h \ $(srcdir)/Include/internal/pycore_optimizer.h \ - $(srcdir)/Python/abstract_interp_cases.c.h + $(srcdir)/Python/tier2_redundancy_eliminator_cases.c.h Python/frozen.o: $(FROZEN_FILES_OUT) diff --git a/Python/optimizer.c b/Python/optimizer.c index e3cff36adab920..b0def4fd10915d 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -824,10 +824,14 @@ uop_optimize( return err; } OPT_STAT_INC(traces_created); - err = _Py_uop_analyze_and_optimize(frame, buffer, - UOP_MAX_TRACE_LENGTH, curr_stackentries, &dependencies); - if (err <= 0) { - return err; + char *uop_optimize = Py_GETENV("PYTHONUOPSOPTIMIZE"); + if (uop_optimize == NULL || *uop_optimize > '0') { + err = _Py_uop_analyze_and_optimize(frame, buffer, + UOP_MAX_TRACE_LENGTH, + curr_stackentries, &dependencies); + if (err <= 0) { + return err; + } } assert(err == 1); _PyExecutorObject *executor = make_executor_from_uops(buffer, &dependencies); diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 39c18709b43a0f..2331653aebb984 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -523,7 +523,8 @@ uop_abstract_interpret_single_inst( _PyOpcode_uop_name[opcode], oparg); switch (opcode) { -#include "abstract_interp_cases.c.h" +#include "tier2_redundancy_eliminator_cases.c.h" + default: DPRINTF(1, "Unknown opcode in abstract interpreter\n"); Py_UNREACHABLE(); diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 11ceaae05879a1..6c042425423640 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1252,7 +1252,7 @@ init_interp_main(PyThreadState *tstate) if (_Py_get_xoption(&config->xoptions, L"uops") != NULL) { enabled = 1; } - enabled = 1; + if (enabled) { #else // Always enable tier two for JIT builds (ignoring the environment diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index e9bb25cff41b68..6d5b67cd6978b9 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -101,45 +101,39 @@ dummy_func(void) { } op(_LOAD_CONST_INLINE, (ptr/4 -- value)) { - _Py_UOpsSymType *sym_const = sym_init_const(ctx, ptr); - if (sym_const == NULL) { + value = sym_init_const(ctx, ptr); + if (value == NULL) { goto error; } - value = sym_const; } op(_LOAD_CONST_INLINE_BORROW, (ptr/4 -- value)) { - _Py_UOpsSymType *sym_const = sym_init_const(ctx, ptr); - if (sym_const == NULL) { + value = sym_init_const(ctx, ptr); + if (value == NULL) { goto error; } - value = sym_const; } op(_LOAD_CONST_INLINE_WITH_NULL, (ptr/4 -- value, null)) { - _Py_UOpsSymType *sym_const = sym_init_const(ctx, ptr); - if (sym_const == NULL) { + value = sym_init_const(ctx, ptr); + if (value == NULL) { goto error; } - value = sym_const; - _Py_UOpsSymType *null_sym = sym_init_null(ctx); - if (null_sym == NULL) { + null = sym_init_null(ctx); + if (null == NULL) { goto error; } - null = null_sym; } op(_LOAD_CONST_INLINE_BORROW_WITH_NULL, (ptr/4 -- value, null)) { - _Py_UOpsSymType *sym_const = sym_init_const(ctx, ptr); - if (sym_const == NULL) { + value = sym_init_const(ctx, ptr); + if (value == NULL) { goto error; } - value = sym_const; - _Py_UOpsSymType *null_sym = sym_init_null(ctx); - if (null_sym == NULL) { + null = sym_init_null(ctx); + if (null == NULL) { goto error; } - null = null_sym; } @@ -208,8 +202,7 @@ dummy_func(void) { assert(self_or_null != NULL); assert(args != NULL); if (sym_matches_type(self_or_null, NOT_NULL)) { - // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in - // VM + // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in VM args--; argcount++; } diff --git a/Python/abstract_interp_cases.c.h b/Python/tier2_redundancy_eliminator_cases.c.h similarity index 98% rename from Python/abstract_interp_cases.c.h rename to Python/tier2_redundancy_eliminator_cases.c.h index dafae2fe5f05fd..568401b8f18663 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/tier2_redundancy_eliminator_cases.c.h @@ -1298,8 +1298,7 @@ assert(self_or_null != NULL); assert(args != NULL); if (sym_matches_type(self_or_null, NOT_NULL)) { - // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in - // VM + // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in VM args--; argcount++; } @@ -1603,11 +1602,10 @@ case _LOAD_CONST_INLINE: { _Py_UOpsSymType *value; PyObject *ptr = (PyObject *)inst->operand; - _Py_UOpsSymType *sym_const = sym_init_const(ctx, ptr); - if (sym_const == NULL) { + value = sym_init_const(ctx, ptr); + if (value == NULL) { goto error; } - value = sym_const; stack_pointer[0] = value; stack_pointer += 1; break; @@ -1616,11 +1614,10 @@ case _LOAD_CONST_INLINE_BORROW: { _Py_UOpsSymType *value; PyObject *ptr = (PyObject *)inst->operand; - _Py_UOpsSymType *sym_const = sym_init_const(ctx, ptr); - if (sym_const == NULL) { + value = sym_init_const(ctx, ptr); + if (value == NULL) { goto error; } - value = sym_const; stack_pointer[0] = value; stack_pointer += 1; break; @@ -1630,16 +1627,14 @@ _Py_UOpsSymType *value; _Py_UOpsSymType *null; PyObject *ptr = (PyObject *)inst->operand; - _Py_UOpsSymType *sym_const = sym_init_const(ctx, ptr); - if (sym_const == NULL) { + value = sym_init_const(ctx, ptr); + if (value == NULL) { goto error; } - value = sym_const; - _Py_UOpsSymType *null_sym = sym_init_null(ctx); - if (null_sym == NULL) { + null = sym_init_null(ctx); + if (null == NULL) { goto error; } - null = null_sym; stack_pointer[0] = value; stack_pointer[1] = null; stack_pointer += 2; @@ -1650,16 +1645,14 @@ _Py_UOpsSymType *value; _Py_UOpsSymType *null; PyObject *ptr = (PyObject *)inst->operand; - _Py_UOpsSymType *sym_const = sym_init_const(ctx, ptr); - if (sym_const == NULL) { + value = sym_init_const(ctx, ptr); + if (value == NULL) { goto error; } - value = sym_const; - _Py_UOpsSymType *null_sym = sym_init_null(ctx); - if (null_sym == NULL) { + null = sym_init_null(ctx); + if (null == NULL) { goto error; } - null = null_sym; stack_pointer[0] = value; stack_pointer[1] = null; stack_pointer += 2; diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index 527c09ea25a1d1..d61d605f5f6c95 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -83,7 +83,7 @@ def clean_lines(text): Python/frozen_modules/*.h Python/generated_cases.c.h Python/executor_cases.c.h -Python/abstract_interp_cases.c.h +Python/tier2_redundancy_eliminator_bytecodes.c.h # not actually source Python/bytecodes.c diff --git a/Tools/cases_generator/README.md b/Tools/cases_generator/README.md index 350779b571a0c7..d35a868b42ea9e 100644 --- a/Tools/cases_generator/README.md +++ b/Tools/cases_generator/README.md @@ -15,7 +15,7 @@ What's currently here: write `Python/generated_cases.c.h` (and several other files) - `tier2_abstract_generator.py`: reads `Python/bytecodes.c` and `Python/tier2_redundancy_eliminator_bytecodes.c` and writes - `Python/abstract_interp_cases.c.h` + `Python/tier2_redundancy_eliminator_cases.c.h` - `stack.py`: code to handle generalized stack effects - `cwriter.py`: code which understands tokens and how to format C code; main class: `CWriter` diff --git a/Tools/cases_generator/tier2_abstract_generator.py b/Tools/cases_generator/tier2_abstract_generator.py index 78037dbcc0ba84..f9ed4b639cd6bf 100644 --- a/Tools/cases_generator/tier2_abstract_generator.py +++ b/Tools/cases_generator/tier2_abstract_generator.py @@ -1,6 +1,6 @@ """Generate the cases for the tier 2 redundancy eliminator/abstract interpreter. Reads the instruction definitions from bytecodes.c. and tier2_redundancy_eliminator.bytecodes.c -Writes the cases to abstract_interp_cases.c.h, which is #included in Python/optimizer_analysis.c. +Writes the cases to tier2_redundancy_eliminator_cases.c.h, which is #included in Python/optimizer_analysis.c. """ import argparse @@ -30,7 +30,7 @@ from lexer import Token from stack import StackOffset, Stack, SizeMismatch, UNUSED -DEFAULT_OUTPUT = ROOT / "Python/abstract_interp_cases.c.h" +DEFAULT_OUTPUT = ROOT / "Python/tier2_redundancy_eliminator_cases.c.h" DEFAULT_ABSTRACT_INPUT = ROOT / "Python/tier2_redundancy_eliminator_bytecodes.c" From 82405fa2d654f3a3ed3d81b9fa0cece47311be8e Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 9 Feb 2024 00:00:35 +0800 Subject: [PATCH 26/52] fix the type system --- Lib/test/test_generated_cases.py | 2 +- Python/optimizer_analysis.c | 158 +++-------- .../tier2_redundancy_eliminator_bytecodes.c | 30 +-- Python/tier2_redundancy_eliminator_cases.c.h | 252 +++++++++--------- .../tier2_abstract_generator.py | 6 +- 5 files changed, 183 insertions(+), 265 deletions(-) diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index c33ec19bc80156..e936834a664db3 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -900,7 +900,7 @@ def test_no_overridden_case(self): output = """ case OP: { _Py_UOpsSymType *out; - out = sym_init_unknown(ctx); + out = sym_new_unknown(ctx); if (out == NULL) goto error; stack_pointer[0] = out; stack_pointer += 1; diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 2331653aebb984..e9f4255628ca15 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -59,38 +59,15 @@ #define DPRINTF(level, ...) #endif -/** -* `PYLONG_TYPE`: `Py_TYPE(val) == &PyLong_Type` -* `PYFLOAT_TYPE`: `Py_TYPE(val) == &PyFloat_Type` -* `PYUNICODE_TYPE`: `Py_TYPE(val) == &PYUNICODE_TYPE` -* `NULL_TYPE`: `val == NULL` -* `PYMETHOD_TYPE`: `Py_TYPE(val) == &PyMethod_Type` -* `PYFUNCTION_TYPE_VERSION_TYPE`: - `PyFunction_Check(callable) && code->co_argcount == oparg + (self_or_null != NULL)` - */ -typedef enum { - // You might think this actually needs to encode oparg - // info as well, see _CHECK_FUNCTION_EXACT_ARGS. - // However, since oparg is tied to code object is tied to function version, - // it should be safe if function version matches. - PYFUNCTION_TYPE_VERSION_TYPE = 2, - - // Types without refinement info - PYLONG_TYPE = 3, - PYFLOAT_TYPE = 4, - PYUNICODE_TYPE = 5, - NULL_TYPE = 6, - PYMETHOD_TYPE = 7, - NOT_NULL = 9, - - // Represents something from LOAD_CONST which is truly constant. - TRUE_CONST = 30, - INVALID_TYPE = 31, -} _Py_UOpsSymExprTypeEnum; + +// Flags for below. +#define KNOWN_TYPE 1 << 0 // Just to differentiate NULL in typ +#define TRUE_CONST 1 << 1 +#define NOT_NULL 1 << 2 typedef struct { - // bitmask of types - uint32_t types; + int flags; + PyTypeObject *typ; // constant propagated value (might be NULL) PyObject *const_val; } _Py_UOpsSymType; @@ -143,11 +120,7 @@ typedef struct _Py_UOpsAbstractInterpContext { _Py_UOpsSymType *locals_and_stack[MAX_ABSTRACT_INTERP_SIZE]; } _Py_UOpsAbstractInterpContext; -static inline _Py_UOpsSymType* -sym_init_const(_Py_UOpsAbstractInterpContext *ctx, PyObject *const_val); - - -static inline _Py_UOpsSymType* sym_init_unknown(_Py_UOpsAbstractInterpContext *ctx); +static inline _Py_UOpsSymType* sym_new_unknown(_Py_UOpsAbstractInterpContext *ctx); // 0 on success, -1 on error. static _Py_UOpsAbstractFrame * @@ -176,7 +149,7 @@ ctx_frame_new( // Initialize with the initial state of all local variables for (int i = n_locals_already_filled; i < co->co_nlocalsplus; i++) { - _Py_UOpsSymType *local = sym_init_unknown(ctx); + _Py_UOpsSymType *local = sym_new_unknown(ctx); if (local == NULL) { return NULL; } @@ -186,7 +159,7 @@ ctx_frame_new( // Initialize the stack as well for (int i = 0; i < curr_stackentries; i++) { - _Py_UOpsSymType *stackvar = sym_init_unknown(ctx); + _Py_UOpsSymType *stackvar = sym_new_unknown(ctx); if (stackvar == NULL) { return NULL; } @@ -265,8 +238,6 @@ ctx_frame_pop( return 0; } -static void -sym_set_type_from_const(_Py_UOpsSymType *sym, PyObject *obj); // Steals a reference to const_val static _Py_UOpsSymType* @@ -281,7 +252,8 @@ _Py_UOpsSymType_New(_Py_UOpsAbstractInterpContext *ctx, } ctx->t_arena.ty_curr_number++; self->const_val = NULL; - self->types = 0; + self->typ = NULL; + self->flags = 0; if (const_val != NULL) { self->const_val = Py_NewRef(const_val); @@ -290,86 +262,46 @@ _Py_UOpsSymType_New(_Py_UOpsAbstractInterpContext *ctx, return self; } - -static void -sym_set_type(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ) +static inline void +sym_set_flag(_Py_UOpsSymType *sym, int flag) { - sym->types |= 1 << typ; + sym->flags |= flag; } - -static _Py_UOpsSymExprTypeEnum -pytype_to_type(PyTypeObject *tp) +static inline bool +sym_has_flag(_Py_UOpsSymType *sym, int flag) { - _Py_UOpsSymExprTypeEnum typ = INVALID_TYPE; - if (tp == NULL) { - typ = NULL_TYPE; - } - else if (tp == &PyLong_Type) { - typ = PYLONG_TYPE; - } - else if (tp == &PyFloat_Type) { - typ = PYFLOAT_TYPE; - } - else if (tp == &PyUnicode_Type) { - typ = PYUNICODE_TYPE; - } - else if (tp == &PyFunction_Type) { - typ = PYFUNCTION_TYPE_VERSION_TYPE; - } - else if (tp == &PyMethod_Type) { - typ = PYMETHOD_TYPE; - } - return typ; + return (sym->flags & flag) != 0; } -static void +static inline void sym_set_pytype(_Py_UOpsSymType *sym, PyTypeObject *tp) { assert(tp == NULL || PyType_Check(tp)); - sym_set_type(sym, pytype_to_type(tp)); + sym->typ = tp; + sym_set_flag(sym, KNOWN_TYPE); } -static void -sym_set_type_from_const(_Py_UOpsSymType *sym, PyObject *obj) -{ - PyTypeObject *tp = Py_TYPE(obj); - - if (tp == &PyFunction_Type) { - sym_set_type(sym, PYFUNCTION_TYPE_VERSION_TYPE); - } - else { - sym_set_pytype(sym, tp); - } - -} static inline _Py_UOpsSymType* -sym_init_unknown(_Py_UOpsAbstractInterpContext *ctx) +sym_new_unknown(_Py_UOpsAbstractInterpContext *ctx) { return _Py_UOpsSymType_New(ctx,NULL); } -static inline bool -sym_is_unknown_type(_Py_UOpsSymType *typ) -{ - return (typ->types == 0) || (typ->types == (1U << INVALID_TYPE)); -} - static inline _Py_UOpsSymType* -sym_init_known_type(_Py_UOpsAbstractInterpContext *ctx, - _Py_UOpsSymExprTypeEnum typ) +sym_new_known_notnull(_Py_UOpsAbstractInterpContext *ctx) { - _Py_UOpsSymType *res = sym_init_unknown(ctx); + _Py_UOpsSymType *res = sym_new_unknown(ctx); if (res == NULL) { return NULL; } - sym_set_type(res, typ); + sym_set_flag(res, NOT_NULL); return res; } static inline _Py_UOpsSymType* -sym_init_known_pytype(_Py_UOpsAbstractInterpContext *ctx, +sym_new_known_pytype(_Py_UOpsAbstractInterpContext *ctx, PyTypeObject *typ) { _Py_UOpsSymType *res = _Py_UOpsSymType_New(ctx,NULL); @@ -382,7 +314,7 @@ sym_init_known_pytype(_Py_UOpsAbstractInterpContext *ctx, // Takes a borrowed reference to const_val. static inline _Py_UOpsSymType* -sym_init_const(_Py_UOpsAbstractInterpContext *ctx, PyObject *const_val) +sym_new_const(_Py_UOpsAbstractInterpContext *ctx, PyObject *const_val) { assert(const_val != NULL); _Py_UOpsSymType *temp = _Py_UOpsSymType_New( @@ -392,49 +324,35 @@ sym_init_const(_Py_UOpsAbstractInterpContext *ctx, PyObject *const_val) if (temp == NULL) { return NULL; } - sym_set_type_from_const(temp, const_val); - sym_set_type(temp, TRUE_CONST); + sym_set_pytype(temp, Py_TYPE(const_val)); + sym_set_flag(temp, TRUE_CONST); return temp; } static _Py_UOpsSymType* -sym_init_null(_Py_UOpsAbstractInterpContext *ctx) +sym_new_null(_Py_UOpsAbstractInterpContext *ctx) { if (ctx->frequent_syms.push_nulL_sym != NULL) { return ctx->frequent_syms.push_nulL_sym; } - _Py_UOpsSymType *null_sym = sym_init_unknown(ctx); + _Py_UOpsSymType *null_sym = sym_new_unknown(ctx); if (null_sym == NULL) { return NULL; } - sym_set_type(null_sym, NULL_TYPE); + sym_set_pytype(null_sym, NULL); ctx->frequent_syms.push_nulL_sym = null_sym; return null_sym; } -static inline bool -sym_is_type(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ) -{ - if ((sym->types & (1 << typ)) == 0) { - return false; - } - return true; -} - -static inline bool -sym_matches_type(_Py_UOpsSymType *sym, _Py_UOpsSymExprTypeEnum typ) -{ - if (!sym_is_type(sym, typ)) { - return false; - } - return true; -} static inline bool sym_matches_pytype(_Py_UOpsSymType *sym, PyTypeObject *typ) { assert(typ == NULL || PyType_Check(typ)); - return sym_matches_type(sym, pytype_to_type(typ)); + if (!sym_has_flag(sym, KNOWN_TYPE)) { + return false; + } + return sym->typ == typ; } @@ -503,11 +421,11 @@ uop_abstract_interpret_single_inst( #define _LOAD_ATTR_NOT_NULL \ do { \ - attr = sym_init_known_type(ctx, NOT_NULL); \ + attr = sym_new_known_notnull(ctx); \ if (attr == NULL) { \ goto error; \ } \ - null = sym_init_null(ctx); \ + null = sym_new_null(ctx); \ if (null == NULL) { \ goto error; \ } \ diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index 6d5b67cd6978b9..3484a341142ba6 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -32,7 +32,7 @@ dummy_func(void) { op(_LOAD_FAST_CHECK, (-- value)) { value = GETLOCAL(oparg); // We guarantee this will error - just bail and don't optimize it. - if (sym_is_type(value, NULL_TYPE)) { + if (sym_matches_pytype(value, NULL)) { goto error; } } @@ -43,7 +43,7 @@ dummy_func(void) { op(_LOAD_FAST_AND_CLEAR, (-- value)) { value = GETLOCAL(oparg); - _Py_UOpsSymType *temp = sym_init_null(ctx); + _Py_UOpsSymType *temp = sym_new_null(ctx); if (temp == NULL) { goto error; } @@ -59,7 +59,7 @@ dummy_func(void) { } op(_PUSH_NULL, (-- res)) { - res = sym_init_null(ctx); + res = sym_new_null(ctx); if (res == NULL) { goto error; }; @@ -88,7 +88,7 @@ dummy_func(void) { // TODO constant propagation (void)left; (void)right; - res = sym_init_known_pytype(ctx, &PyLong_Type); + res = sym_new_known_pytype(ctx, &PyLong_Type); if (res == NULL) { goto error; } @@ -101,36 +101,36 @@ dummy_func(void) { } op(_LOAD_CONST_INLINE, (ptr/4 -- value)) { - value = sym_init_const(ctx, ptr); + value = sym_new_const(ctx, ptr); if (value == NULL) { goto error; } } op(_LOAD_CONST_INLINE_BORROW, (ptr/4 -- value)) { - value = sym_init_const(ctx, ptr); + value = sym_new_const(ctx, ptr); if (value == NULL) { goto error; } } op(_LOAD_CONST_INLINE_WITH_NULL, (ptr/4 -- value, null)) { - value = sym_init_const(ctx, ptr); + value = sym_new_const(ctx, ptr); if (value == NULL) { goto error; } - null = sym_init_null(ctx); + null = sym_new_null(ctx); if (null == NULL) { goto error; } } op(_LOAD_CONST_INLINE_BORROW_WITH_NULL, (ptr/4 -- value, null)) { - value = sym_init_const(ctx, ptr); + value = sym_new_const(ctx, ptr); if (value == NULL) { goto error; } - null = sym_init_null(ctx); + null = sym_new_null(ctx); if (null == NULL) { goto error; } @@ -201,7 +201,7 @@ dummy_func(void) { assert(self_or_null != NULL); assert(args != NULL); - if (sym_matches_type(self_or_null, NOT_NULL)) { + if (sym_has_flag(self_or_null, NOT_NULL)) { // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in VM args--; argcount++; @@ -212,7 +212,7 @@ dummy_func(void) { // Can determine statically, so we interleave the new locals // and make the current stack the new locals. // This also sets up for true call inlining. - if (!sym_is_unknown_type(self_or_null)) { + if (sym_has_flag(self_or_null, KNOWN_TYPE)) { localsplus_start = args; n_locals_already_filled = argcount; } @@ -242,7 +242,7 @@ dummy_func(void) { /* This has to be done manually */ (void)seq; for (int i = 0; i < oparg; i++) { - values[i] = sym_init_unknown(ctx); + values[i] = sym_new_unknown(ctx); if (values[i] == NULL) { goto error; } @@ -254,7 +254,7 @@ dummy_func(void) { (void)seq; int totalargs = (oparg & 0xFF) + (oparg >> 8) + 1; for (int i = 0; i < totalargs; i++) { - values[i] = sym_init_unknown(ctx); + values[i] = sym_new_unknown(ctx); if (values[i] == NULL) { goto error; } @@ -262,7 +262,7 @@ dummy_func(void) { } op(_ITER_NEXT_RANGE, (iter -- iter, next)) { - next = sym_init_known_pytype(ctx, &PyLong_Type); + next = sym_new_known_pytype(ctx, &PyLong_Type); if (next == NULL) { goto error; } diff --git a/Python/tier2_redundancy_eliminator_cases.c.h b/Python/tier2_redundancy_eliminator_cases.c.h index 568401b8f18663..f1453bdcd039b6 100644 --- a/Python/tier2_redundancy_eliminator_cases.c.h +++ b/Python/tier2_redundancy_eliminator_cases.c.h @@ -17,7 +17,7 @@ _Py_UOpsSymType *value; value = GETLOCAL(oparg); // We guarantee this will error - just bail and don't optimize it. - if (sym_is_type(value, NULL_TYPE)) { + if (sym_matches_pytype(value, NULL)) { goto error; } stack_pointer[0] = value; @@ -36,7 +36,7 @@ case _LOAD_FAST_AND_CLEAR: { _Py_UOpsSymType *value; value = GETLOCAL(oparg); - _Py_UOpsSymType *temp = sym_init_null(ctx); + _Py_UOpsSymType *temp = sym_new_null(ctx); if (temp == NULL) { goto error; } @@ -70,7 +70,7 @@ case _PUSH_NULL: { _Py_UOpsSymType *res; - res = sym_init_null(ctx); + res = sym_new_null(ctx); if (res == NULL) { goto error; }; @@ -81,7 +81,7 @@ case _END_SEND: { _Py_UOpsSymType *value; - value = sym_init_unknown(ctx); + value = sym_new_unknown(ctx); if (value == NULL) goto error; stack_pointer[0] = value; stack_pointer += 1; @@ -90,7 +90,7 @@ case _UNARY_NEGATIVE: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -99,7 +99,7 @@ case _UNARY_NOT: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -108,7 +108,7 @@ case _TO_BOOL: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -121,7 +121,7 @@ case _TO_BOOL_INT: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -130,7 +130,7 @@ case _TO_BOOL_LIST: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -139,7 +139,7 @@ case _TO_BOOL_NONE: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -148,7 +148,7 @@ case _TO_BOOL_STR: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -157,7 +157,7 @@ case _TO_BOOL_ALWAYS_TRUE: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -166,7 +166,7 @@ case _UNARY_INVERT: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -189,7 +189,7 @@ case _BINARY_OP_MULTIPLY_INT: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -205,7 +205,7 @@ // TODO constant propagation (void)left; (void)right; - res = sym_init_known_pytype(ctx, &PyLong_Type); + res = sym_new_known_pytype(ctx, &PyLong_Type); if (res == NULL) { goto error; } @@ -216,7 +216,7 @@ case _BINARY_OP_SUBTRACT_INT: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -239,7 +239,7 @@ case _BINARY_OP_MULTIPLY_FLOAT: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -248,7 +248,7 @@ case _BINARY_OP_ADD_FLOAT: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -257,7 +257,7 @@ case _BINARY_OP_SUBTRACT_FLOAT: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -270,7 +270,7 @@ case _BINARY_OP_ADD_UNICODE: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -279,7 +279,7 @@ case _BINARY_SUBSCR: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -288,7 +288,7 @@ case _BINARY_SLICE: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -301,7 +301,7 @@ case _BINARY_SUBSCR_LIST_INT: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -310,7 +310,7 @@ case _BINARY_SUBSCR_STR_INT: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -319,7 +319,7 @@ case _BINARY_SUBSCR_TUPLE_INT: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -328,7 +328,7 @@ case _BINARY_SUBSCR_DICT: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -363,7 +363,7 @@ case _CALL_INTRINSIC_1: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -372,7 +372,7 @@ case _CALL_INTRINSIC_2: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -399,7 +399,7 @@ case _GET_AITER: { _Py_UOpsSymType *iter; - iter = sym_init_unknown(ctx); + iter = sym_new_unknown(ctx); if (iter == NULL) goto error; stack_pointer[0] = iter; stack_pointer += 1; @@ -408,7 +408,7 @@ case _GET_ANEXT: { _Py_UOpsSymType *awaitable; - awaitable = sym_init_unknown(ctx); + awaitable = sym_new_unknown(ctx); if (awaitable == NULL) goto error; stack_pointer[0] = awaitable; stack_pointer += 1; @@ -417,7 +417,7 @@ case _GET_AWAITABLE: { _Py_UOpsSymType *iter; - iter = sym_init_unknown(ctx); + iter = sym_new_unknown(ctx); if (iter == NULL) goto error; stack_pointer[0] = iter; stack_pointer += 1; @@ -436,7 +436,7 @@ case _LOAD_ASSERTION_ERROR: { _Py_UOpsSymType *value; - value = sym_init_unknown(ctx); + value = sym_new_unknown(ctx); if (value == NULL) goto error; stack_pointer[0] = value; stack_pointer += 1; @@ -445,7 +445,7 @@ case _LOAD_BUILD_CLASS: { _Py_UOpsSymType *bc; - bc = sym_init_unknown(ctx); + bc = sym_new_unknown(ctx); if (bc == NULL) goto error; stack_pointer[0] = bc; stack_pointer += 1; @@ -468,7 +468,7 @@ /* This has to be done manually */ (void)seq; for (int i = 0; i < oparg; i++) { - values[i] = sym_init_unknown(ctx); + values[i] = sym_new_unknown(ctx); if (values[i] == NULL) { goto error; } @@ -481,7 +481,7 @@ _Py_UOpsSymType **values; values = &stack_pointer[0]; for (int _i = oparg; --_i >= 0;) { - values[_i] = sym_init_unknown(ctx); + values[_i] = sym_new_unknown(ctx); if (values[_i] == NULL) goto error; } stack_pointer += oparg; @@ -492,7 +492,7 @@ _Py_UOpsSymType **values; values = &stack_pointer[0]; for (int _i = oparg; --_i >= 0;) { - values[_i] = sym_init_unknown(ctx); + values[_i] = sym_new_unknown(ctx); if (values[_i] == NULL) goto error; } stack_pointer += oparg; @@ -503,7 +503,7 @@ _Py_UOpsSymType **values; values = &stack_pointer[0]; for (int _i = oparg; --_i >= 0;) { - values[_i] = sym_init_unknown(ctx); + values[_i] = sym_new_unknown(ctx); if (values[_i] == NULL) goto error; } stack_pointer += oparg; @@ -519,7 +519,7 @@ (void)seq; int totalargs = (oparg & 0xFF) + (oparg >> 8) + 1; for (int i = 0; i < totalargs; i++) { - values[i] = sym_init_unknown(ctx); + values[i] = sym_new_unknown(ctx); if (values[i] == NULL) { goto error; } @@ -546,7 +546,7 @@ case _LOAD_LOCALS: { _Py_UOpsSymType *locals; - locals = sym_init_unknown(ctx); + locals = sym_new_unknown(ctx); if (locals == NULL) goto error; stack_pointer[0] = locals; stack_pointer += 1; @@ -555,7 +555,7 @@ case _LOAD_FROM_DICT_OR_GLOBALS: { _Py_UOpsSymType *v; - v = sym_init_unknown(ctx); + v = sym_new_unknown(ctx); if (v == NULL) goto error; stack_pointer[0] = v; stack_pointer += 1; @@ -564,7 +564,7 @@ case _LOAD_NAME: { _Py_UOpsSymType *v; - v = sym_init_unknown(ctx); + v = sym_new_unknown(ctx); if (v == NULL) goto error; stack_pointer[0] = v; stack_pointer += 1; @@ -574,9 +574,9 @@ case _LOAD_GLOBAL: { _Py_UOpsSymType *res; _Py_UOpsSymType *null = NULL; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; - null = sym_init_null(ctx); + null = sym_new_null(ctx); if (null == NULL) goto error; stack_pointer[0] = res; if (oparg & 1) stack_pointer[1] = null; @@ -595,9 +595,9 @@ case _LOAD_GLOBAL_MODULE: { _Py_UOpsSymType *res; _Py_UOpsSymType *null = NULL; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; - null = sym_init_null(ctx); + null = sym_new_null(ctx); if (null == NULL) goto error; stack_pointer[0] = res; if (oparg & 1) stack_pointer[1] = null; @@ -608,9 +608,9 @@ case _LOAD_GLOBAL_BUILTINS: { _Py_UOpsSymType *res; _Py_UOpsSymType *null = NULL; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; - null = sym_init_null(ctx); + null = sym_new_null(ctx); if (null == NULL) goto error; stack_pointer[0] = res; if (oparg & 1) stack_pointer[1] = null; @@ -632,7 +632,7 @@ case _LOAD_FROM_DICT_OR_DEREF: { _Py_UOpsSymType *value; - value = sym_init_unknown(ctx); + value = sym_new_unknown(ctx); if (value == NULL) goto error; stack_pointer[0] = value; stack_pointer += 1; @@ -641,7 +641,7 @@ case _LOAD_DEREF: { _Py_UOpsSymType *value; - value = sym_init_unknown(ctx); + value = sym_new_unknown(ctx); if (value == NULL) goto error; stack_pointer[0] = value; stack_pointer += 1; @@ -658,7 +658,7 @@ case _BUILD_STRING: { _Py_UOpsSymType *str; - str = sym_init_unknown(ctx); + str = sym_new_unknown(ctx); if (str == NULL) goto error; stack_pointer[0] = str; stack_pointer += 1; @@ -667,7 +667,7 @@ case _BUILD_TUPLE: { _Py_UOpsSymType *tup; - tup = sym_init_unknown(ctx); + tup = sym_new_unknown(ctx); if (tup == NULL) goto error; stack_pointer[0] = tup; stack_pointer += 1; @@ -676,7 +676,7 @@ case _BUILD_LIST: { _Py_UOpsSymType *list; - list = sym_init_unknown(ctx); + list = sym_new_unknown(ctx); if (list == NULL) goto error; stack_pointer[0] = list; stack_pointer += 1; @@ -693,7 +693,7 @@ case _BUILD_SET: { _Py_UOpsSymType *set; - set = sym_init_unknown(ctx); + set = sym_new_unknown(ctx); if (set == NULL) goto error; stack_pointer[0] = set; stack_pointer += 1; @@ -702,7 +702,7 @@ case _BUILD_MAP: { _Py_UOpsSymType *map; - map = sym_init_unknown(ctx); + map = sym_new_unknown(ctx); if (map == NULL) goto error; stack_pointer[0] = map; stack_pointer += 1; @@ -715,7 +715,7 @@ case _BUILD_CONST_KEY_MAP: { _Py_UOpsSymType *map; - map = sym_init_unknown(ctx); + map = sym_new_unknown(ctx); if (map == NULL) goto error; stack_pointer[0] = map; stack_pointer += 1; @@ -738,7 +738,7 @@ case _LOAD_SUPER_ATTR_ATTR: { _Py_UOpsSymType *attr; - attr = sym_init_unknown(ctx); + attr = sym_new_unknown(ctx); if (attr == NULL) goto error; stack_pointer[0] = attr; stack_pointer += 1 + ((0) ? 1 : 0); @@ -748,9 +748,9 @@ case _LOAD_SUPER_ATTR_METHOD: { _Py_UOpsSymType *attr; _Py_UOpsSymType *self_or_null; - attr = sym_init_unknown(ctx); + attr = sym_new_unknown(ctx); if (attr == NULL) goto error; - self_or_null = sym_init_unknown(ctx); + self_or_null = sym_new_unknown(ctx); if (self_or_null == NULL) goto error; stack_pointer[0] = attr; stack_pointer[1] = self_or_null; @@ -761,9 +761,9 @@ case _LOAD_ATTR: { _Py_UOpsSymType *attr; _Py_UOpsSymType *self_or_null = NULL; - attr = sym_init_unknown(ctx); + attr = sym_new_unknown(ctx); if (attr == NULL) goto error; - self_or_null = sym_init_unknown(ctx); + self_or_null = sym_new_unknown(ctx); if (self_or_null == NULL) goto error; stack_pointer[0] = attr; if (oparg & 1) stack_pointer[1] = self_or_null; @@ -886,7 +886,7 @@ case _COMPARE_OP: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -895,7 +895,7 @@ case _COMPARE_OP_FLOAT: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -904,7 +904,7 @@ case _COMPARE_OP_INT: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -913,7 +913,7 @@ case _COMPARE_OP_STR: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -922,7 +922,7 @@ case _IS_OP: { _Py_UOpsSymType *b; - b = sym_init_unknown(ctx); + b = sym_new_unknown(ctx); if (b == NULL) goto error; stack_pointer[0] = b; stack_pointer += 1; @@ -931,7 +931,7 @@ case _CONTAINS_OP: { _Py_UOpsSymType *b; - b = sym_init_unknown(ctx); + b = sym_new_unknown(ctx); if (b == NULL) goto error; stack_pointer[0] = b; stack_pointer += 1; @@ -941,9 +941,9 @@ case _CHECK_EG_MATCH: { _Py_UOpsSymType *rest; _Py_UOpsSymType *match; - rest = sym_init_unknown(ctx); + rest = sym_new_unknown(ctx); if (rest == NULL) goto error; - match = sym_init_unknown(ctx); + match = sym_new_unknown(ctx); if (match == NULL) goto error; stack_pointer[0] = rest; stack_pointer[1] = match; @@ -953,7 +953,7 @@ case _CHECK_EXC_MATCH: { _Py_UOpsSymType *b; - b = sym_init_unknown(ctx); + b = sym_new_unknown(ctx); if (b == NULL) goto error; stack_pointer[0] = b; stack_pointer += 1; @@ -968,7 +968,7 @@ case _IS_NONE: { _Py_UOpsSymType *b; - b = sym_init_unknown(ctx); + b = sym_new_unknown(ctx); if (b == NULL) goto error; stack_pointer[0] = b; stack_pointer += 1; @@ -977,7 +977,7 @@ case _GET_LEN: { _Py_UOpsSymType *len_o; - len_o = sym_init_unknown(ctx); + len_o = sym_new_unknown(ctx); if (len_o == NULL) goto error; stack_pointer[0] = len_o; stack_pointer += 1; @@ -986,7 +986,7 @@ case _MATCH_CLASS: { _Py_UOpsSymType *attrs; - attrs = sym_init_unknown(ctx); + attrs = sym_new_unknown(ctx); if (attrs == NULL) goto error; stack_pointer[0] = attrs; stack_pointer += 1; @@ -995,7 +995,7 @@ case _MATCH_MAPPING: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1004,7 +1004,7 @@ case _MATCH_SEQUENCE: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1013,7 +1013,7 @@ case _MATCH_KEYS: { _Py_UOpsSymType *values_or_none; - values_or_none = sym_init_unknown(ctx); + values_or_none = sym_new_unknown(ctx); if (values_or_none == NULL) goto error; stack_pointer[0] = values_or_none; stack_pointer += 1; @@ -1022,7 +1022,7 @@ case _GET_ITER: { _Py_UOpsSymType *iter; - iter = sym_init_unknown(ctx); + iter = sym_new_unknown(ctx); if (iter == NULL) goto error; stack_pointer[0] = iter; stack_pointer += 1; @@ -1031,7 +1031,7 @@ case _GET_YIELD_FROM_ITER: { _Py_UOpsSymType *iter; - iter = sym_init_unknown(ctx); + iter = sym_new_unknown(ctx); if (iter == NULL) goto error; stack_pointer[0] = iter; stack_pointer += 1; @@ -1042,7 +1042,7 @@ case _FOR_ITER_TIER_TWO: { _Py_UOpsSymType *next; - next = sym_init_unknown(ctx); + next = sym_new_unknown(ctx); if (next == NULL) goto error; stack_pointer[0] = next; stack_pointer += 1; @@ -1063,7 +1063,7 @@ case _ITER_NEXT_LIST: { _Py_UOpsSymType *next; - next = sym_init_unknown(ctx); + next = sym_new_unknown(ctx); if (next == NULL) goto error; stack_pointer[0] = next; stack_pointer += 1; @@ -1082,7 +1082,7 @@ case _ITER_NEXT_TUPLE: { _Py_UOpsSymType *next; - next = sym_init_unknown(ctx); + next = sym_new_unknown(ctx); if (next == NULL) goto error; stack_pointer[0] = next; stack_pointer += 1; @@ -1103,7 +1103,7 @@ _Py_UOpsSymType *iter; _Py_UOpsSymType *next; iter = stack_pointer[-1]; - next = sym_init_known_pytype(ctx, &PyLong_Type); + next = sym_new_known_pytype(ctx, &PyLong_Type); if (next == NULL) { goto error; } @@ -1118,9 +1118,9 @@ case _BEFORE_ASYNC_WITH: { _Py_UOpsSymType *exit; _Py_UOpsSymType *res; - exit = sym_init_unknown(ctx); + exit = sym_new_unknown(ctx); if (exit == NULL) goto error; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = exit; stack_pointer[1] = res; @@ -1131,9 +1131,9 @@ case _BEFORE_WITH: { _Py_UOpsSymType *exit; _Py_UOpsSymType *res; - exit = sym_init_unknown(ctx); + exit = sym_new_unknown(ctx); if (exit == NULL) goto error; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = exit; stack_pointer[1] = res; @@ -1143,7 +1143,7 @@ case _WITH_EXCEPT_START: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1153,9 +1153,9 @@ case _PUSH_EXC_INFO: { _Py_UOpsSymType *prev_exc; _Py_UOpsSymType *new_exc; - prev_exc = sym_init_unknown(ctx); + prev_exc = sym_new_unknown(ctx); if (prev_exc == NULL) goto error; - new_exc = sym_init_unknown(ctx); + new_exc = sym_new_unknown(ctx); if (new_exc == NULL) goto error; stack_pointer[0] = prev_exc; stack_pointer[1] = new_exc; @@ -1174,9 +1174,9 @@ case _LOAD_ATTR_METHOD_WITH_VALUES: { _Py_UOpsSymType *attr; _Py_UOpsSymType *self = NULL; - attr = sym_init_unknown(ctx); + attr = sym_new_unknown(ctx); if (attr == NULL) goto error; - self = sym_init_unknown(ctx); + self = sym_new_unknown(ctx); if (self == NULL) goto error; stack_pointer[0] = attr; if (1) stack_pointer[1] = self; @@ -1187,9 +1187,9 @@ case _LOAD_ATTR_METHOD_NO_DICT: { _Py_UOpsSymType *attr; _Py_UOpsSymType *self = NULL; - attr = sym_init_unknown(ctx); + attr = sym_new_unknown(ctx); if (attr == NULL) goto error; - self = sym_init_unknown(ctx); + self = sym_new_unknown(ctx); if (self == NULL) goto error; stack_pointer[0] = attr; if (1) stack_pointer[1] = self; @@ -1199,7 +1199,7 @@ case _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: { _Py_UOpsSymType *attr; - attr = sym_init_unknown(ctx); + attr = sym_new_unknown(ctx); if (attr == NULL) goto error; stack_pointer[0] = attr; stack_pointer += 1 + ((0) ? 1 : 0); @@ -1208,7 +1208,7 @@ case _LOAD_ATTR_NONDESCRIPTOR_NO_DICT: { _Py_UOpsSymType *attr; - attr = sym_init_unknown(ctx); + attr = sym_new_unknown(ctx); if (attr == NULL) goto error; stack_pointer[0] = attr; stack_pointer += 1 + ((0) ? 1 : 0); @@ -1222,9 +1222,9 @@ case _LOAD_ATTR_METHOD_LAZY_DICT: { _Py_UOpsSymType *attr; _Py_UOpsSymType *self = NULL; - attr = sym_init_unknown(ctx); + attr = sym_new_unknown(ctx); if (attr == NULL) goto error; - self = sym_init_unknown(ctx); + self = sym_new_unknown(ctx); if (self == NULL) goto error; stack_pointer[0] = attr; if (1) stack_pointer[1] = self; @@ -1249,9 +1249,9 @@ case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: { _Py_UOpsSymType *func; _Py_UOpsSymType *self; - func = sym_init_unknown(ctx); + func = sym_new_unknown(ctx); if (func == NULL) goto error; - self = sym_init_unknown(ctx); + self = sym_new_unknown(ctx); if (self == NULL) goto error; stack_pointer[0] = func; stack_pointer[1] = self; @@ -1297,7 +1297,7 @@ PyCodeObject *co = (PyCodeObject *)func->func_code; assert(self_or_null != NULL); assert(args != NULL); - if (sym_matches_type(self_or_null, NOT_NULL)) { + if (sym_has_flag(self_or_null, NOT_NULL)) { // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in VM args--; argcount++; @@ -1307,7 +1307,7 @@ // Can determine statically, so we interleave the new locals // and make the current stack the new locals. // This also sets up for true call inlining. - if (!sym_is_unknown_type(self_or_null)) { + if (sym_has_flag(self_or_null, KNOWN_TYPE)) { localsplus_start = args; n_locals_already_filled = argcount; } @@ -1336,7 +1336,7 @@ case _CALL_TYPE_1: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1345,7 +1345,7 @@ case _CALL_STR_1: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1354,7 +1354,7 @@ case _CALL_TUPLE_1: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1369,7 +1369,7 @@ case _CALL_BUILTIN_CLASS: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1378,7 +1378,7 @@ case _CALL_BUILTIN_O: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1387,7 +1387,7 @@ case _CALL_BUILTIN_FAST: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1396,7 +1396,7 @@ case _CALL_BUILTIN_FAST_WITH_KEYWORDS: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1405,7 +1405,7 @@ case _CALL_LEN: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1414,7 +1414,7 @@ case _CALL_ISINSTANCE: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1423,7 +1423,7 @@ case _CALL_METHOD_DESCRIPTOR_O: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1432,7 +1432,7 @@ case _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1441,7 +1441,7 @@ case _CALL_METHOD_DESCRIPTOR_NOARGS: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1450,7 +1450,7 @@ case _CALL_METHOD_DESCRIPTOR_FAST: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1467,7 +1467,7 @@ case _MAKE_FUNCTION: { _Py_UOpsSymType *func; - func = sym_init_unknown(ctx); + func = sym_new_unknown(ctx); if (func == NULL) goto error; stack_pointer[0] = func; stack_pointer += 1; @@ -1476,7 +1476,7 @@ case _SET_FUNCTION_ATTRIBUTE: { _Py_UOpsSymType *func; - func = sym_init_unknown(ctx); + func = sym_new_unknown(ctx); if (func == NULL) goto error; stack_pointer[0] = func; stack_pointer += 1; @@ -1485,7 +1485,7 @@ case _BUILD_SLICE: { _Py_UOpsSymType *slice; - slice = sym_init_unknown(ctx); + slice = sym_new_unknown(ctx); if (slice == NULL) goto error; stack_pointer[0] = slice; stack_pointer += 1; @@ -1494,7 +1494,7 @@ case _CONVERT_VALUE: { _Py_UOpsSymType *result; - result = sym_init_unknown(ctx); + result = sym_new_unknown(ctx); if (result == NULL) goto error; stack_pointer[0] = result; stack_pointer += 1; @@ -1503,7 +1503,7 @@ case _FORMAT_SIMPLE: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1512,7 +1512,7 @@ case _FORMAT_WITH_SPEC: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1532,7 +1532,7 @@ case _BINARY_OP: { _Py_UOpsSymType *res; - res = sym_init_unknown(ctx); + res = sym_new_unknown(ctx); if (res == NULL) goto error; stack_pointer[0] = res; stack_pointer += 1; @@ -1602,7 +1602,7 @@ case _LOAD_CONST_INLINE: { _Py_UOpsSymType *value; PyObject *ptr = (PyObject *)inst->operand; - value = sym_init_const(ctx, ptr); + value = sym_new_const(ctx, ptr); if (value == NULL) { goto error; } @@ -1614,7 +1614,7 @@ case _LOAD_CONST_INLINE_BORROW: { _Py_UOpsSymType *value; PyObject *ptr = (PyObject *)inst->operand; - value = sym_init_const(ctx, ptr); + value = sym_new_const(ctx, ptr); if (value == NULL) { goto error; } @@ -1627,11 +1627,11 @@ _Py_UOpsSymType *value; _Py_UOpsSymType *null; PyObject *ptr = (PyObject *)inst->operand; - value = sym_init_const(ctx, ptr); + value = sym_new_const(ctx, ptr); if (value == NULL) { goto error; } - null = sym_init_null(ctx); + null = sym_new_null(ctx); if (null == NULL) { goto error; } @@ -1645,11 +1645,11 @@ _Py_UOpsSymType *value; _Py_UOpsSymType *null; PyObject *ptr = (PyObject *)inst->operand; - value = sym_init_const(ctx, ptr); + value = sym_new_const(ctx, ptr); if (value == NULL) { goto error; } - null = sym_init_null(ctx); + null = sym_new_null(ctx); if (null == NULL) { goto error; } diff --git a/Tools/cases_generator/tier2_abstract_generator.py b/Tools/cases_generator/tier2_abstract_generator.py index f9ed4b639cd6bf..c3450d9268c0cf 100644 --- a/Tools/cases_generator/tier2_abstract_generator.py +++ b/Tools/cases_generator/tier2_abstract_generator.py @@ -87,14 +87,14 @@ def emit_default(out: CWriter, uop: Uop) -> None: if var.name != "unused" and not var.peek: if var.is_array(): out.emit(f"for (int _i = {var.size}; --_i >= 0;) {{\n") - out.emit(f"{var.name}[_i] = sym_init_unknown(ctx);\n") + out.emit(f"{var.name}[_i] = sym_new_unknown(ctx);\n") out.emit(f"if ({var.name}[_i] == NULL) goto error;\n") out.emit("}\n") elif var.name == "null": - out.emit(f"{var.name} = sym_init_null(ctx);\n") + out.emit(f"{var.name} = sym_new_null(ctx);\n") out.emit(f"if ({var.name} == NULL) goto error;\n") else: - out.emit(f"{var.name} = sym_init_unknown(ctx);\n") + out.emit(f"{var.name} = sym_new_unknown(ctx);\n") out.emit(f"if ({var.name} == NULL) goto error;\n") From 2e31906484e7172ad6991d316d6b99097e023084 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 9 Feb 2024 00:22:19 +0800 Subject: [PATCH 27/52] fix cases generator --- Lib/test/test_generated_cases.py | 33 +- Python/tier2_redundancy_eliminator_cases.c.h | 348 +++++++++--------- .../tier2_abstract_generator.py | 6 +- 3 files changed, 208 insertions(+), 179 deletions(-) diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index e936834a664db3..89a70b6e6c4c4b 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -868,6 +868,10 @@ def test_overridden_abstract_args(self): pure op(OP, (arg1 -- out)) { spam(); } + + op(OP2, (arg1 -- out)) { + eggs(); + } """ input2 = """ op(OP, (arg1 -- out)) { @@ -883,7 +887,15 @@ def test_overridden_abstract_args(self): stack_pointer[-1] = out; break; } - """ + + case OP2: { + _Py_UOpsSymType *out; + out = sym_new_unknown(ctx); + if (out == NULL) goto error; + stack_pointer[-1] = out; + break; + } + """ self.run_cases_test(input, input2, output) def test_no_overridden_case(self): @@ -891,10 +903,14 @@ def test_no_overridden_case(self): pure op(OP, (arg1 -- out)) { spam(); } + + pure op(OP2, (arg1 -- out)) { + } + """ input2 = """ - pure op(OTHER, (arg1 -- out)) { - spam(); + pure op(OP2, (arg1 -- out)) { + } """ output = """ @@ -902,10 +918,17 @@ def test_no_overridden_case(self): _Py_UOpsSymType *out; out = sym_new_unknown(ctx); if (out == NULL) goto error; - stack_pointer[0] = out; - stack_pointer += 1; + stack_pointer[-1] = out; break; } + + case OP2: { + _Py_UOpsSymType *arg1; + _Py_UOpsSymType *out; + arg1 = stack_pointer[-1]; + stack_pointer[-1] = out; + break; + } """ self.run_cases_test(input, input2, output) diff --git a/Python/tier2_redundancy_eliminator_cases.c.h b/Python/tier2_redundancy_eliminator_cases.c.h index f1453bdcd039b6..20e7b232bd1f22 100644 --- a/Python/tier2_redundancy_eliminator_cases.c.h +++ b/Python/tier2_redundancy_eliminator_cases.c.h @@ -65,6 +65,7 @@ } case _POP_TOP: { + stack_pointer += -1; break; } @@ -83,8 +84,8 @@ _Py_UOpsSymType *value; value = sym_new_unknown(ctx); if (value == NULL) goto error; - stack_pointer[0] = value; - stack_pointer += 1; + stack_pointer[-2] = value; + stack_pointer += -1; break; } @@ -92,8 +93,7 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-1] = res; break; } @@ -101,8 +101,7 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-1] = res; break; } @@ -110,8 +109,7 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-1] = res; break; } @@ -123,8 +121,7 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-1] = res; break; } @@ -132,8 +129,7 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-1] = res; break; } @@ -141,8 +137,7 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-1] = res; break; } @@ -150,8 +145,7 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-1] = res; break; } @@ -159,8 +153,7 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-1] = res; break; } @@ -168,8 +161,7 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-1] = res; break; } @@ -191,8 +183,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2] = res; + stack_pointer += -1; break; } @@ -218,8 +210,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2] = res; + stack_pointer += -1; break; } @@ -241,8 +233,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2] = res; + stack_pointer += -1; break; } @@ -250,8 +242,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2] = res; + stack_pointer += -1; break; } @@ -259,8 +251,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2] = res; + stack_pointer += -1; break; } @@ -272,8 +264,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2] = res; + stack_pointer += -1; break; } @@ -281,8 +273,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2] = res; + stack_pointer += -1; break; } @@ -290,12 +282,13 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-3] = res; + stack_pointer += -2; break; } case _STORE_SLICE: { + stack_pointer += -4; break; } @@ -303,8 +296,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2] = res; + stack_pointer += -1; break; } @@ -312,8 +305,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2] = res; + stack_pointer += -1; break; } @@ -321,8 +314,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2] = res; + stack_pointer += -1; break; } @@ -330,34 +323,40 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2] = res; + stack_pointer += -1; break; } /* _BINARY_SUBSCR_GETITEM is not a viable micro-op for tier 2 */ case _LIST_APPEND: { + stack_pointer += -1; break; } case _SET_ADD: { + stack_pointer += -1; break; } case _STORE_SUBSCR: { + stack_pointer += -3; break; } case _STORE_SUBSCR_LIST_INT: { + stack_pointer += -3; break; } case _STORE_SUBSCR_DICT: { + stack_pointer += -3; break; } case _DELETE_SUBSCR: { + stack_pointer += -2; break; } @@ -365,8 +364,7 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-1] = res; break; } @@ -374,8 +372,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2] = res; + stack_pointer += -1; break; } @@ -401,8 +399,7 @@ _Py_UOpsSymType *iter; iter = sym_new_unknown(ctx); if (iter == NULL) goto error; - stack_pointer[0] = iter; - stack_pointer += 1; + stack_pointer[-1] = iter; break; } @@ -419,8 +416,7 @@ _Py_UOpsSymType *iter; iter = sym_new_unknown(ctx); if (iter == NULL) goto error; - stack_pointer[0] = iter; - stack_pointer += 1; + stack_pointer[-1] = iter; break; } @@ -431,6 +427,7 @@ /* _INSTRUMENTED_YIELD_VALUE is not a viable micro-op for tier 2 */ case _POP_EXCEPT: { + stack_pointer += -1; break; } @@ -453,6 +450,7 @@ } case _STORE_NAME: { + stack_pointer += -1; break; } @@ -479,34 +477,34 @@ case _UNPACK_SEQUENCE_TWO_TUPLE: { _Py_UOpsSymType **values; - values = &stack_pointer[0]; + values = &stack_pointer[-1]; for (int _i = oparg; --_i >= 0;) { values[_i] = sym_new_unknown(ctx); if (values[_i] == NULL) goto error; } - stack_pointer += oparg; + stack_pointer += -1 + oparg; break; } case _UNPACK_SEQUENCE_TUPLE: { _Py_UOpsSymType **values; - values = &stack_pointer[0]; + values = &stack_pointer[-1]; for (int _i = oparg; --_i >= 0;) { values[_i] = sym_new_unknown(ctx); if (values[_i] == NULL) goto error; } - stack_pointer += oparg; + stack_pointer += -1 + oparg; break; } case _UNPACK_SEQUENCE_LIST: { _Py_UOpsSymType **values; - values = &stack_pointer[0]; + values = &stack_pointer[-1]; for (int _i = oparg; --_i >= 0;) { values[_i] = sym_new_unknown(ctx); if (values[_i] == NULL) goto error; } - stack_pointer += oparg; + stack_pointer += -1 + oparg; break; } @@ -529,14 +527,17 @@ } case _STORE_ATTR: { + stack_pointer += -2; break; } case _DELETE_ATTR: { + stack_pointer += -1; break; } case _STORE_GLOBAL: { + stack_pointer += -1; break; } @@ -557,8 +558,7 @@ _Py_UOpsSymType *v; v = sym_new_unknown(ctx); if (v == NULL) goto error; - stack_pointer[0] = v; - stack_pointer += 1; + stack_pointer[-1] = v; break; } @@ -634,8 +634,7 @@ _Py_UOpsSymType *value; value = sym_new_unknown(ctx); if (value == NULL) goto error; - stack_pointer[0] = value; - stack_pointer += 1; + stack_pointer[-1] = value; break; } @@ -649,6 +648,7 @@ } case _STORE_DEREF: { + stack_pointer += -1; break; } @@ -660,8 +660,8 @@ _Py_UOpsSymType *str; str = sym_new_unknown(ctx); if (str == NULL) goto error; - stack_pointer[0] = str; - stack_pointer += 1; + stack_pointer[-oparg] = str; + stack_pointer += 1 - oparg; break; } @@ -669,8 +669,8 @@ _Py_UOpsSymType *tup; tup = sym_new_unknown(ctx); if (tup == NULL) goto error; - stack_pointer[0] = tup; - stack_pointer += 1; + stack_pointer[-oparg] = tup; + stack_pointer += 1 - oparg; break; } @@ -678,16 +678,18 @@ _Py_UOpsSymType *list; list = sym_new_unknown(ctx); if (list == NULL) goto error; - stack_pointer[0] = list; - stack_pointer += 1; + stack_pointer[-oparg] = list; + stack_pointer += 1 - oparg; break; } case _LIST_EXTEND: { + stack_pointer += -1; break; } case _SET_UPDATE: { + stack_pointer += -1; break; } @@ -695,8 +697,8 @@ _Py_UOpsSymType *set; set = sym_new_unknown(ctx); if (set == NULL) goto error; - stack_pointer[0] = set; - stack_pointer += 1; + stack_pointer[-oparg] = set; + stack_pointer += 1 - oparg; break; } @@ -704,8 +706,8 @@ _Py_UOpsSymType *map; map = sym_new_unknown(ctx); if (map == NULL) goto error; - stack_pointer[0] = map; - stack_pointer += 1; + stack_pointer[-oparg*2] = map; + stack_pointer += 1 - oparg*2; break; } @@ -717,20 +719,23 @@ _Py_UOpsSymType *map; map = sym_new_unknown(ctx); if (map == NULL) goto error; - stack_pointer[0] = map; - stack_pointer += 1; + stack_pointer[-1 - oparg] = map; + stack_pointer += -oparg; break; } case _DICT_UPDATE: { + stack_pointer += -1; break; } case _DICT_MERGE: { + stack_pointer += -1; break; } case _MAP_ADD: { + stack_pointer += -2; break; } @@ -740,8 +745,8 @@ _Py_UOpsSymType *attr; attr = sym_new_unknown(ctx); if (attr == NULL) goto error; - stack_pointer[0] = attr; - stack_pointer += 1 + ((0) ? 1 : 0); + stack_pointer[-3] = attr; + stack_pointer += -2 + ((0) ? 1 : 0); break; } @@ -752,9 +757,9 @@ if (attr == NULL) goto error; self_or_null = sym_new_unknown(ctx); if (self_or_null == NULL) goto error; - stack_pointer[0] = attr; - stack_pointer[1] = self_or_null; - stack_pointer += 2; + stack_pointer[-3] = attr; + stack_pointer[-2] = self_or_null; + stack_pointer += -1; break; } @@ -765,9 +770,9 @@ if (attr == NULL) goto error; self_or_null = sym_new_unknown(ctx); if (self_or_null == NULL) goto error; - stack_pointer[0] = attr; - if (oparg & 1) stack_pointer[1] = self_or_null; - stack_pointer += 1 + (oparg & 1); + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = self_or_null; + stack_pointer += (oparg & 1); break; } @@ -875,12 +880,14 @@ } case _STORE_ATTR_INSTANCE_VALUE: { + stack_pointer += -2; break; } /* _STORE_ATTR_WITH_HINT is not a viable micro-op for tier 2 */ case _STORE_ATTR_SLOT: { + stack_pointer += -2; break; } @@ -888,8 +895,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2] = res; + stack_pointer += -1; break; } @@ -897,8 +904,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2] = res; + stack_pointer += -1; break; } @@ -906,8 +913,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2] = res; + stack_pointer += -1; break; } @@ -915,8 +922,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2] = res; + stack_pointer += -1; break; } @@ -924,8 +931,8 @@ _Py_UOpsSymType *b; b = sym_new_unknown(ctx); if (b == NULL) goto error; - stack_pointer[0] = b; - stack_pointer += 1; + stack_pointer[-2] = b; + stack_pointer += -1; break; } @@ -933,8 +940,8 @@ _Py_UOpsSymType *b; b = sym_new_unknown(ctx); if (b == NULL) goto error; - stack_pointer[0] = b; - stack_pointer += 1; + stack_pointer[-2] = b; + stack_pointer += -1; break; } @@ -945,9 +952,8 @@ if (rest == NULL) goto error; match = sym_new_unknown(ctx); if (match == NULL) goto error; - stack_pointer[0] = rest; - stack_pointer[1] = match; - stack_pointer += 2; + stack_pointer[-2] = rest; + stack_pointer[-1] = match; break; } @@ -955,8 +961,7 @@ _Py_UOpsSymType *b; b = sym_new_unknown(ctx); if (b == NULL) goto error; - stack_pointer[0] = b; - stack_pointer += 1; + stack_pointer[-1] = b; break; } @@ -970,8 +975,7 @@ _Py_UOpsSymType *b; b = sym_new_unknown(ctx); if (b == NULL) goto error; - stack_pointer[0] = b; - stack_pointer += 1; + stack_pointer[-1] = b; break; } @@ -988,8 +992,8 @@ _Py_UOpsSymType *attrs; attrs = sym_new_unknown(ctx); if (attrs == NULL) goto error; - stack_pointer[0] = attrs; - stack_pointer += 1; + stack_pointer[-3] = attrs; + stack_pointer += -2; break; } @@ -1024,8 +1028,7 @@ _Py_UOpsSymType *iter; iter = sym_new_unknown(ctx); if (iter == NULL) goto error; - stack_pointer[0] = iter; - stack_pointer += 1; + stack_pointer[-1] = iter; break; } @@ -1033,8 +1036,7 @@ _Py_UOpsSymType *iter; iter = sym_new_unknown(ctx); if (iter == NULL) goto error; - stack_pointer[0] = iter; - stack_pointer += 1; + stack_pointer[-1] = iter; break; } @@ -1122,9 +1124,9 @@ if (exit == NULL) goto error; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = exit; - stack_pointer[1] = res; - stack_pointer += 2; + stack_pointer[-1] = exit; + stack_pointer[0] = res; + stack_pointer += 1; break; } @@ -1135,9 +1137,9 @@ if (exit == NULL) goto error; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = exit; - stack_pointer[1] = res; - stack_pointer += 2; + stack_pointer[-1] = exit; + stack_pointer[0] = res; + stack_pointer += 1; break; } @@ -1157,9 +1159,9 @@ if (prev_exc == NULL) goto error; new_exc = sym_new_unknown(ctx); if (new_exc == NULL) goto error; - stack_pointer[0] = prev_exc; - stack_pointer[1] = new_exc; - stack_pointer += 2; + stack_pointer[-1] = prev_exc; + stack_pointer[0] = new_exc; + stack_pointer += 1; break; } @@ -1178,9 +1180,9 @@ if (attr == NULL) goto error; self = sym_new_unknown(ctx); if (self == NULL) goto error; - stack_pointer[0] = attr; - if (1) stack_pointer[1] = self; - stack_pointer += 1 + ((1) ? 1 : 0); + stack_pointer[-1] = attr; + if (1) stack_pointer[0] = self; + stack_pointer += ((1) ? 1 : 0); break; } @@ -1191,9 +1193,9 @@ if (attr == NULL) goto error; self = sym_new_unknown(ctx); if (self == NULL) goto error; - stack_pointer[0] = attr; - if (1) stack_pointer[1] = self; - stack_pointer += 1 + ((1) ? 1 : 0); + stack_pointer[-1] = attr; + if (1) stack_pointer[0] = self; + stack_pointer += ((1) ? 1 : 0); break; } @@ -1201,8 +1203,8 @@ _Py_UOpsSymType *attr; attr = sym_new_unknown(ctx); if (attr == NULL) goto error; - stack_pointer[0] = attr; - stack_pointer += 1 + ((0) ? 1 : 0); + stack_pointer[-1] = attr; + stack_pointer += ((0) ? 1 : 0); break; } @@ -1210,8 +1212,8 @@ _Py_UOpsSymType *attr; attr = sym_new_unknown(ctx); if (attr == NULL) goto error; - stack_pointer[0] = attr; - stack_pointer += 1 + ((0) ? 1 : 0); + stack_pointer[-1] = attr; + stack_pointer += ((0) ? 1 : 0); break; } @@ -1226,9 +1228,9 @@ if (attr == NULL) goto error; self = sym_new_unknown(ctx); if (self == NULL) goto error; - stack_pointer[0] = attr; - if (1) stack_pointer[1] = self; - stack_pointer += 1 + ((1) ? 1 : 0); + stack_pointer[-1] = attr; + if (1) stack_pointer[0] = self; + stack_pointer += ((1) ? 1 : 0); break; } @@ -1253,9 +1255,8 @@ if (func == NULL) goto error; self = sym_new_unknown(ctx); if (self == NULL) goto error; - stack_pointer[0] = func; - stack_pointer[1] = self; - stack_pointer += 2; + stack_pointer[-2 - oparg] = func; + stack_pointer[-1 - oparg] = self; break; } @@ -1338,8 +1339,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; break; } @@ -1347,8 +1348,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; break; } @@ -1356,14 +1357,15 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; break; } /* _CALL_ALLOC_AND_ENTER_INIT is not a viable micro-op for tier 2 */ case _EXIT_INIT_CHECK: { + stack_pointer += -1; break; } @@ -1371,8 +1373,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; break; } @@ -1380,8 +1382,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; break; } @@ -1389,8 +1391,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; break; } @@ -1398,8 +1400,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; break; } @@ -1407,8 +1409,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; break; } @@ -1416,8 +1418,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; break; } @@ -1425,8 +1427,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; break; } @@ -1434,8 +1436,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; break; } @@ -1443,8 +1445,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; break; } @@ -1452,8 +1454,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; break; } @@ -1469,8 +1471,7 @@ _Py_UOpsSymType *func; func = sym_new_unknown(ctx); if (func == NULL) goto error; - stack_pointer[0] = func; - stack_pointer += 1; + stack_pointer[-1] = func; break; } @@ -1478,8 +1479,8 @@ _Py_UOpsSymType *func; func = sym_new_unknown(ctx); if (func == NULL) goto error; - stack_pointer[0] = func; - stack_pointer += 1; + stack_pointer[-2] = func; + stack_pointer += -1; break; } @@ -1487,8 +1488,8 @@ _Py_UOpsSymType *slice; slice = sym_new_unknown(ctx); if (slice == NULL) goto error; - stack_pointer[0] = slice; - stack_pointer += 1; + stack_pointer[-2 - ((oparg == 3) ? 1 : 0)] = slice; + stack_pointer += -1 - ((oparg == 3) ? 1 : 0); break; } @@ -1496,8 +1497,7 @@ _Py_UOpsSymType *result; result = sym_new_unknown(ctx); if (result == NULL) goto error; - stack_pointer[0] = result; - stack_pointer += 1; + stack_pointer[-1] = result; break; } @@ -1505,8 +1505,7 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-1] = res; break; } @@ -1514,8 +1513,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2] = res; + stack_pointer += -1; break; } @@ -1534,8 +1533,8 @@ _Py_UOpsSymType *res; res = sym_new_unknown(ctx); if (res == NULL) goto error; - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2] = res; + stack_pointer += -1; break; } @@ -1564,18 +1563,22 @@ /* _INSTRUMENTED_POP_JUMP_IF_NOT_NONE is not a viable micro-op for tier 2 */ case _GUARD_IS_TRUE_POP: { + stack_pointer += -1; break; } case _GUARD_IS_FALSE_POP: { + stack_pointer += -1; break; } case _GUARD_IS_NONE_POP: { + stack_pointer += -1; break; } case _GUARD_IS_NOT_NONE_POP: { + stack_pointer += -1; break; } @@ -1668,6 +1671,7 @@ } case _INTERNAL_INCREMENT_OPT_COUNTER: { + stack_pointer += -1; break; } diff --git a/Tools/cases_generator/tier2_abstract_generator.py b/Tools/cases_generator/tier2_abstract_generator.py index c3450d9268c0cf..e3a6de41fdaf8b 100644 --- a/Tools/cases_generator/tier2_abstract_generator.py +++ b/Tools/cases_generator/tier2_abstract_generator.py @@ -111,12 +111,14 @@ def write_uop( is_override = override is not None out.start_line() for var in reversed(prototype.stack.inputs): + res = stack.pop(var) if not skip_inputs: - out.emit(stack.pop(var)) + out.emit(res) if not prototype.properties.stores_sp: for i, var in enumerate(prototype.stack.outputs): + res = stack.push(var) if not var.peek or is_override: - out.emit(stack.push(var)) + out.emit(res) if debug: args = [] for var in prototype.stack.inputs: From ed25ce05343e9514c85c1d821c3bd9dc322b76e3 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 9 Feb 2024 00:26:40 +0800 Subject: [PATCH 28/52] remove whitespace --- Lib/test/test_generated_cases.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index 89a70b6e6c4c4b..b7311e22662846 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -868,7 +868,6 @@ def test_overridden_abstract_args(self): pure op(OP, (arg1 -- out)) { spam(); } - op(OP2, (arg1 -- out)) { eggs(); } @@ -903,14 +902,13 @@ def test_no_overridden_case(self): pure op(OP, (arg1 -- out)) { spam(); } - + pure op(OP2, (arg1 -- out)) { } - + """ input2 = """ pure op(OP2, (arg1 -- out)) { - } """ output = """ @@ -928,7 +926,7 @@ def test_no_overridden_case(self): arg1 = stack_pointer[-1]; stack_pointer[-1] = out; break; - } + } """ self.run_cases_test(input, input2, output) From 3bf3c7d39a2366af48a8a0d88443661ec8d80deb Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 9 Feb 2024 00:40:34 +0800 Subject: [PATCH 29/52] check all overridden uops are originally defined --- Lib/test/test_generated_cases.py | 15 +++++++++++++++ Python/tier2_redundancy_eliminator_bytecodes.c | 4 ---- Tools/cases_generator/tier2_abstract_generator.py | 5 +++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index b7311e22662846..f552ee5a088eff 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -930,6 +930,21 @@ def test_no_overridden_case(self): """ self.run_cases_test(input, input2, output) + def test_missing_override_failure(self): + input = """ + pure op(OP, (arg1 -- out)) { + spam(); + } + """ + input2 = """ + pure op(OTHER, (arg1 -- out)) { + } + """ + output = """ + """ + with self.assertRaisesRegex(AssertionError, "All abstract uops"): + self.run_cases_test(input, input2, output) + if __name__ == "__main__": unittest.main() diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index 3484a341142ba6..02e650bdec9af5 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -54,10 +54,6 @@ dummy_func(void) { GETLOCAL(oparg) = value; } - op(_STORE_FAST_MAYBE_NULL, (value --)) { - GETLOCAL(oparg) = value; - } - op(_PUSH_NULL, (-- res)) { res = sym_new_null(ctx); if (res == NULL) { diff --git a/Tools/cases_generator/tier2_abstract_generator.py b/Tools/cases_generator/tier2_abstract_generator.py index e3a6de41fdaf8b..846c7dda7a348d 100644 --- a/Tools/cases_generator/tier2_abstract_generator.py +++ b/Tools/cases_generator/tier2_abstract_generator.py @@ -166,6 +166,11 @@ def generate_abstract_interpreter( write_header(__file__, filenames, outfile) out = CWriter(outfile, 2, False) out.emit("\n") + base_uop_names = set([uop.name for uop in base.uops.values()]) + for abstract_uop_name in abstract.uops: + assert abstract_uop_name in base_uop_names,\ + f"All abstract uops should override base uops, but {abstract_uop_name} is not." + for uop in base.uops.values(): override: Uop | None = None if uop.name in abstract.uops: From 2af5b742f93e00e5939aae11d9ad0575b609793b Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 9 Feb 2024 00:48:37 +0800 Subject: [PATCH 30/52] error -> out of space --- Python/optimizer_analysis.c | 8 +- .../tier2_redundancy_eliminator_bytecodes.c | 30 +-- Python/tier2_redundancy_eliminator_cases.c.h | 252 +++++++++--------- .../tier2_abstract_generator.py | 6 +- 4 files changed, 151 insertions(+), 145 deletions(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index e9f4255628ca15..62e88f3e664795 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -453,11 +453,17 @@ uop_abstract_interpret_single_inst( assert(STACK_LEVEL() >= 0); if (emit_i(&ctx->emitter, new_inst) < 0) { - return -1; + goto error; } return 0; +out_of_space: + DPRINTF(1, "Out of space in abstract interpreter\n"); + if (emit_i(&ctx->emitter, new_inst) < 0) { + goto error; + } + return 0; error: DPRINTF(1, "Encountered error in abstract interpreter\n"); return -1; diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index 02e650bdec9af5..3ea44c4474dfa1 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -33,7 +33,7 @@ dummy_func(void) { value = GETLOCAL(oparg); // We guarantee this will error - just bail and don't optimize it. if (sym_matches_pytype(value, NULL)) { - goto error; + goto out_of_space; } } @@ -45,7 +45,7 @@ dummy_func(void) { value = GETLOCAL(oparg); _Py_UOpsSymType *temp = sym_new_null(ctx); if (temp == NULL) { - goto error; + goto out_of_space; } GETLOCAL(oparg) = temp; } @@ -57,7 +57,7 @@ dummy_func(void) { op(_PUSH_NULL, (-- res)) { res = sym_new_null(ctx); if (res == NULL) { - goto error; + goto out_of_space; }; } @@ -86,7 +86,7 @@ dummy_func(void) { (void)right; res = sym_new_known_pytype(ctx, &PyLong_Type); if (res == NULL) { - goto error; + goto out_of_space; } } @@ -99,36 +99,36 @@ dummy_func(void) { op(_LOAD_CONST_INLINE, (ptr/4 -- value)) { value = sym_new_const(ctx, ptr); if (value == NULL) { - goto error; + goto out_of_space; } } op(_LOAD_CONST_INLINE_BORROW, (ptr/4 -- value)) { value = sym_new_const(ctx, ptr); if (value == NULL) { - goto error; + goto out_of_space; } } op(_LOAD_CONST_INLINE_WITH_NULL, (ptr/4 -- value, null)) { value = sym_new_const(ctx, ptr); if (value == NULL) { - goto error; + goto out_of_space; } null = sym_new_null(ctx); if (null == NULL) { - goto error; + goto out_of_space; } } op(_LOAD_CONST_INLINE_BORROW_WITH_NULL, (ptr/4 -- value, null)) { value = sym_new_const(ctx, ptr); if (value == NULL) { - goto error; + goto out_of_space; } null = sym_new_null(ctx); if (null == NULL) { - goto error; + goto out_of_space; } } @@ -191,7 +191,7 @@ dummy_func(void) { assert((inst + 2)->opcode == _PUSH_FRAME); PyFunctionObject *func = (PyFunctionObject *)(inst + 2)->operand; if (func == NULL) { - goto error; + goto out_of_space; } PyCodeObject *co = (PyCodeObject *)func->func_code; @@ -214,7 +214,7 @@ dummy_func(void) { } new_frame = ctx_frame_new(ctx, co, localsplus_start, n_locals_already_filled, 0); if (new_frame == NULL){ - goto error; + goto out_of_space; } } @@ -240,7 +240,7 @@ dummy_func(void) { for (int i = 0; i < oparg; i++) { values[i] = sym_new_unknown(ctx); if (values[i] == NULL) { - goto error; + goto out_of_space; } } } @@ -252,7 +252,7 @@ dummy_func(void) { for (int i = 0; i < totalargs; i++) { values[i] = sym_new_unknown(ctx); if (values[i] == NULL) { - goto error; + goto out_of_space; } } } @@ -260,7 +260,7 @@ dummy_func(void) { op(_ITER_NEXT_RANGE, (iter -- iter, next)) { next = sym_new_known_pytype(ctx, &PyLong_Type); if (next == NULL) { - goto error; + goto out_of_space; } (void)iter; } diff --git a/Python/tier2_redundancy_eliminator_cases.c.h b/Python/tier2_redundancy_eliminator_cases.c.h index 20e7b232bd1f22..4fa721e6043193 100644 --- a/Python/tier2_redundancy_eliminator_cases.c.h +++ b/Python/tier2_redundancy_eliminator_cases.c.h @@ -18,7 +18,7 @@ value = GETLOCAL(oparg); // We guarantee this will error - just bail and don't optimize it. if (sym_matches_pytype(value, NULL)) { - goto error; + goto out_of_space; } stack_pointer[0] = value; stack_pointer += 1; @@ -38,7 +38,7 @@ value = GETLOCAL(oparg); _Py_UOpsSymType *temp = sym_new_null(ctx); if (temp == NULL) { - goto error; + goto out_of_space; } GETLOCAL(oparg) = temp; stack_pointer[0] = value; @@ -73,7 +73,7 @@ _Py_UOpsSymType *res; res = sym_new_null(ctx); if (res == NULL) { - goto error; + goto out_of_space; }; stack_pointer[0] = res; stack_pointer += 1; @@ -83,7 +83,7 @@ case _END_SEND: { _Py_UOpsSymType *value; value = sym_new_unknown(ctx); - if (value == NULL) goto error; + if (value == NULL) goto out_of_space; stack_pointer[-2] = value; stack_pointer += -1; break; @@ -92,7 +92,7 @@ case _UNARY_NEGATIVE: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-1] = res; break; } @@ -100,7 +100,7 @@ case _UNARY_NOT: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-1] = res; break; } @@ -108,7 +108,7 @@ case _TO_BOOL: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-1] = res; break; } @@ -120,7 +120,7 @@ case _TO_BOOL_INT: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-1] = res; break; } @@ -128,7 +128,7 @@ case _TO_BOOL_LIST: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-1] = res; break; } @@ -136,7 +136,7 @@ case _TO_BOOL_NONE: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-1] = res; break; } @@ -144,7 +144,7 @@ case _TO_BOOL_STR: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-1] = res; break; } @@ -152,7 +152,7 @@ case _TO_BOOL_ALWAYS_TRUE: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-1] = res; break; } @@ -160,7 +160,7 @@ case _UNARY_INVERT: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-1] = res; break; } @@ -182,7 +182,7 @@ case _BINARY_OP_MULTIPLY_INT: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; break; @@ -199,7 +199,7 @@ (void)right; res = sym_new_known_pytype(ctx, &PyLong_Type); if (res == NULL) { - goto error; + goto out_of_space; } stack_pointer[-2] = res; stack_pointer += -1; @@ -209,7 +209,7 @@ case _BINARY_OP_SUBTRACT_INT: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; break; @@ -232,7 +232,7 @@ case _BINARY_OP_MULTIPLY_FLOAT: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; break; @@ -241,7 +241,7 @@ case _BINARY_OP_ADD_FLOAT: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; break; @@ -250,7 +250,7 @@ case _BINARY_OP_SUBTRACT_FLOAT: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; break; @@ -263,7 +263,7 @@ case _BINARY_OP_ADD_UNICODE: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; break; @@ -272,7 +272,7 @@ case _BINARY_SUBSCR: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; break; @@ -281,7 +281,7 @@ case _BINARY_SLICE: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-3] = res; stack_pointer += -2; break; @@ -295,7 +295,7 @@ case _BINARY_SUBSCR_LIST_INT: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; break; @@ -304,7 +304,7 @@ case _BINARY_SUBSCR_STR_INT: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; break; @@ -313,7 +313,7 @@ case _BINARY_SUBSCR_TUPLE_INT: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; break; @@ -322,7 +322,7 @@ case _BINARY_SUBSCR_DICT: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; break; @@ -363,7 +363,7 @@ case _CALL_INTRINSIC_1: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-1] = res; break; } @@ -371,7 +371,7 @@ case _CALL_INTRINSIC_2: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; break; @@ -398,7 +398,7 @@ case _GET_AITER: { _Py_UOpsSymType *iter; iter = sym_new_unknown(ctx); - if (iter == NULL) goto error; + if (iter == NULL) goto out_of_space; stack_pointer[-1] = iter; break; } @@ -406,7 +406,7 @@ case _GET_ANEXT: { _Py_UOpsSymType *awaitable; awaitable = sym_new_unknown(ctx); - if (awaitable == NULL) goto error; + if (awaitable == NULL) goto out_of_space; stack_pointer[0] = awaitable; stack_pointer += 1; break; @@ -415,7 +415,7 @@ case _GET_AWAITABLE: { _Py_UOpsSymType *iter; iter = sym_new_unknown(ctx); - if (iter == NULL) goto error; + if (iter == NULL) goto out_of_space; stack_pointer[-1] = iter; break; } @@ -434,7 +434,7 @@ case _LOAD_ASSERTION_ERROR: { _Py_UOpsSymType *value; value = sym_new_unknown(ctx); - if (value == NULL) goto error; + if (value == NULL) goto out_of_space; stack_pointer[0] = value; stack_pointer += 1; break; @@ -443,7 +443,7 @@ case _LOAD_BUILD_CLASS: { _Py_UOpsSymType *bc; bc = sym_new_unknown(ctx); - if (bc == NULL) goto error; + if (bc == NULL) goto out_of_space; stack_pointer[0] = bc; stack_pointer += 1; break; @@ -468,7 +468,7 @@ for (int i = 0; i < oparg; i++) { values[i] = sym_new_unknown(ctx); if (values[i] == NULL) { - goto error; + goto out_of_space; } } stack_pointer += -1 + oparg; @@ -480,7 +480,7 @@ values = &stack_pointer[-1]; for (int _i = oparg; --_i >= 0;) { values[_i] = sym_new_unknown(ctx); - if (values[_i] == NULL) goto error; + if (values[_i] == NULL) goto out_of_space; } stack_pointer += -1 + oparg; break; @@ -491,7 +491,7 @@ values = &stack_pointer[-1]; for (int _i = oparg; --_i >= 0;) { values[_i] = sym_new_unknown(ctx); - if (values[_i] == NULL) goto error; + if (values[_i] == NULL) goto out_of_space; } stack_pointer += -1 + oparg; break; @@ -502,7 +502,7 @@ values = &stack_pointer[-1]; for (int _i = oparg; --_i >= 0;) { values[_i] = sym_new_unknown(ctx); - if (values[_i] == NULL) goto error; + if (values[_i] == NULL) goto out_of_space; } stack_pointer += -1 + oparg; break; @@ -519,7 +519,7 @@ for (int i = 0; i < totalargs; i++) { values[i] = sym_new_unknown(ctx); if (values[i] == NULL) { - goto error; + goto out_of_space; } } stack_pointer += (oparg >> 8) + (oparg & 0xFF); @@ -548,7 +548,7 @@ case _LOAD_LOCALS: { _Py_UOpsSymType *locals; locals = sym_new_unknown(ctx); - if (locals == NULL) goto error; + if (locals == NULL) goto out_of_space; stack_pointer[0] = locals; stack_pointer += 1; break; @@ -557,7 +557,7 @@ case _LOAD_FROM_DICT_OR_GLOBALS: { _Py_UOpsSymType *v; v = sym_new_unknown(ctx); - if (v == NULL) goto error; + if (v == NULL) goto out_of_space; stack_pointer[-1] = v; break; } @@ -565,7 +565,7 @@ case _LOAD_NAME: { _Py_UOpsSymType *v; v = sym_new_unknown(ctx); - if (v == NULL) goto error; + if (v == NULL) goto out_of_space; stack_pointer[0] = v; stack_pointer += 1; break; @@ -575,9 +575,9 @@ _Py_UOpsSymType *res; _Py_UOpsSymType *null = NULL; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; null = sym_new_null(ctx); - if (null == NULL) goto error; + if (null == NULL) goto out_of_space; stack_pointer[0] = res; if (oparg & 1) stack_pointer[1] = null; stack_pointer += 1 + (oparg & 1); @@ -596,9 +596,9 @@ _Py_UOpsSymType *res; _Py_UOpsSymType *null = NULL; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; null = sym_new_null(ctx); - if (null == NULL) goto error; + if (null == NULL) goto out_of_space; stack_pointer[0] = res; if (oparg & 1) stack_pointer[1] = null; stack_pointer += 1 + (oparg & 1); @@ -609,9 +609,9 @@ _Py_UOpsSymType *res; _Py_UOpsSymType *null = NULL; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; null = sym_new_null(ctx); - if (null == NULL) goto error; + if (null == NULL) goto out_of_space; stack_pointer[0] = res; if (oparg & 1) stack_pointer[1] = null; stack_pointer += 1 + (oparg & 1); @@ -633,7 +633,7 @@ case _LOAD_FROM_DICT_OR_DEREF: { _Py_UOpsSymType *value; value = sym_new_unknown(ctx); - if (value == NULL) goto error; + if (value == NULL) goto out_of_space; stack_pointer[-1] = value; break; } @@ -641,7 +641,7 @@ case _LOAD_DEREF: { _Py_UOpsSymType *value; value = sym_new_unknown(ctx); - if (value == NULL) goto error; + if (value == NULL) goto out_of_space; stack_pointer[0] = value; stack_pointer += 1; break; @@ -659,7 +659,7 @@ case _BUILD_STRING: { _Py_UOpsSymType *str; str = sym_new_unknown(ctx); - if (str == NULL) goto error; + if (str == NULL) goto out_of_space; stack_pointer[-oparg] = str; stack_pointer += 1 - oparg; break; @@ -668,7 +668,7 @@ case _BUILD_TUPLE: { _Py_UOpsSymType *tup; tup = sym_new_unknown(ctx); - if (tup == NULL) goto error; + if (tup == NULL) goto out_of_space; stack_pointer[-oparg] = tup; stack_pointer += 1 - oparg; break; @@ -677,7 +677,7 @@ case _BUILD_LIST: { _Py_UOpsSymType *list; list = sym_new_unknown(ctx); - if (list == NULL) goto error; + if (list == NULL) goto out_of_space; stack_pointer[-oparg] = list; stack_pointer += 1 - oparg; break; @@ -696,7 +696,7 @@ case _BUILD_SET: { _Py_UOpsSymType *set; set = sym_new_unknown(ctx); - if (set == NULL) goto error; + if (set == NULL) goto out_of_space; stack_pointer[-oparg] = set; stack_pointer += 1 - oparg; break; @@ -705,7 +705,7 @@ case _BUILD_MAP: { _Py_UOpsSymType *map; map = sym_new_unknown(ctx); - if (map == NULL) goto error; + if (map == NULL) goto out_of_space; stack_pointer[-oparg*2] = map; stack_pointer += 1 - oparg*2; break; @@ -718,7 +718,7 @@ case _BUILD_CONST_KEY_MAP: { _Py_UOpsSymType *map; map = sym_new_unknown(ctx); - if (map == NULL) goto error; + if (map == NULL) goto out_of_space; stack_pointer[-1 - oparg] = map; stack_pointer += -oparg; break; @@ -744,7 +744,7 @@ case _LOAD_SUPER_ATTR_ATTR: { _Py_UOpsSymType *attr; attr = sym_new_unknown(ctx); - if (attr == NULL) goto error; + if (attr == NULL) goto out_of_space; stack_pointer[-3] = attr; stack_pointer += -2 + ((0) ? 1 : 0); break; @@ -754,9 +754,9 @@ _Py_UOpsSymType *attr; _Py_UOpsSymType *self_or_null; attr = sym_new_unknown(ctx); - if (attr == NULL) goto error; + if (attr == NULL) goto out_of_space; self_or_null = sym_new_unknown(ctx); - if (self_or_null == NULL) goto error; + if (self_or_null == NULL) goto out_of_space; stack_pointer[-3] = attr; stack_pointer[-2] = self_or_null; stack_pointer += -1; @@ -767,9 +767,9 @@ _Py_UOpsSymType *attr; _Py_UOpsSymType *self_or_null = NULL; attr = sym_new_unknown(ctx); - if (attr == NULL) goto error; + if (attr == NULL) goto out_of_space; self_or_null = sym_new_unknown(ctx); - if (self_or_null == NULL) goto error; + if (self_or_null == NULL) goto out_of_space; stack_pointer[-1] = attr; if (oparg & 1) stack_pointer[0] = self_or_null; stack_pointer += (oparg & 1); @@ -894,7 +894,7 @@ case _COMPARE_OP: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; break; @@ -903,7 +903,7 @@ case _COMPARE_OP_FLOAT: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; break; @@ -912,7 +912,7 @@ case _COMPARE_OP_INT: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; break; @@ -921,7 +921,7 @@ case _COMPARE_OP_STR: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; break; @@ -930,7 +930,7 @@ case _IS_OP: { _Py_UOpsSymType *b; b = sym_new_unknown(ctx); - if (b == NULL) goto error; + if (b == NULL) goto out_of_space; stack_pointer[-2] = b; stack_pointer += -1; break; @@ -939,7 +939,7 @@ case _CONTAINS_OP: { _Py_UOpsSymType *b; b = sym_new_unknown(ctx); - if (b == NULL) goto error; + if (b == NULL) goto out_of_space; stack_pointer[-2] = b; stack_pointer += -1; break; @@ -949,9 +949,9 @@ _Py_UOpsSymType *rest; _Py_UOpsSymType *match; rest = sym_new_unknown(ctx); - if (rest == NULL) goto error; + if (rest == NULL) goto out_of_space; match = sym_new_unknown(ctx); - if (match == NULL) goto error; + if (match == NULL) goto out_of_space; stack_pointer[-2] = rest; stack_pointer[-1] = match; break; @@ -960,7 +960,7 @@ case _CHECK_EXC_MATCH: { _Py_UOpsSymType *b; b = sym_new_unknown(ctx); - if (b == NULL) goto error; + if (b == NULL) goto out_of_space; stack_pointer[-1] = b; break; } @@ -974,7 +974,7 @@ case _IS_NONE: { _Py_UOpsSymType *b; b = sym_new_unknown(ctx); - if (b == NULL) goto error; + if (b == NULL) goto out_of_space; stack_pointer[-1] = b; break; } @@ -982,7 +982,7 @@ case _GET_LEN: { _Py_UOpsSymType *len_o; len_o = sym_new_unknown(ctx); - if (len_o == NULL) goto error; + if (len_o == NULL) goto out_of_space; stack_pointer[0] = len_o; stack_pointer += 1; break; @@ -991,7 +991,7 @@ case _MATCH_CLASS: { _Py_UOpsSymType *attrs; attrs = sym_new_unknown(ctx); - if (attrs == NULL) goto error; + if (attrs == NULL) goto out_of_space; stack_pointer[-3] = attrs; stack_pointer += -2; break; @@ -1000,7 +1000,7 @@ case _MATCH_MAPPING: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[0] = res; stack_pointer += 1; break; @@ -1009,7 +1009,7 @@ case _MATCH_SEQUENCE: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[0] = res; stack_pointer += 1; break; @@ -1018,7 +1018,7 @@ case _MATCH_KEYS: { _Py_UOpsSymType *values_or_none; values_or_none = sym_new_unknown(ctx); - if (values_or_none == NULL) goto error; + if (values_or_none == NULL) goto out_of_space; stack_pointer[0] = values_or_none; stack_pointer += 1; break; @@ -1027,7 +1027,7 @@ case _GET_ITER: { _Py_UOpsSymType *iter; iter = sym_new_unknown(ctx); - if (iter == NULL) goto error; + if (iter == NULL) goto out_of_space; stack_pointer[-1] = iter; break; } @@ -1035,7 +1035,7 @@ case _GET_YIELD_FROM_ITER: { _Py_UOpsSymType *iter; iter = sym_new_unknown(ctx); - if (iter == NULL) goto error; + if (iter == NULL) goto out_of_space; stack_pointer[-1] = iter; break; } @@ -1045,7 +1045,7 @@ case _FOR_ITER_TIER_TWO: { _Py_UOpsSymType *next; next = sym_new_unknown(ctx); - if (next == NULL) goto error; + if (next == NULL) goto out_of_space; stack_pointer[0] = next; stack_pointer += 1; break; @@ -1066,7 +1066,7 @@ case _ITER_NEXT_LIST: { _Py_UOpsSymType *next; next = sym_new_unknown(ctx); - if (next == NULL) goto error; + if (next == NULL) goto out_of_space; stack_pointer[0] = next; stack_pointer += 1; break; @@ -1085,7 +1085,7 @@ case _ITER_NEXT_TUPLE: { _Py_UOpsSymType *next; next = sym_new_unknown(ctx); - if (next == NULL) goto error; + if (next == NULL) goto out_of_space; stack_pointer[0] = next; stack_pointer += 1; break; @@ -1107,7 +1107,7 @@ iter = stack_pointer[-1]; next = sym_new_known_pytype(ctx, &PyLong_Type); if (next == NULL) { - goto error; + goto out_of_space; } (void)iter; stack_pointer[0] = next; @@ -1121,9 +1121,9 @@ _Py_UOpsSymType *exit; _Py_UOpsSymType *res; exit = sym_new_unknown(ctx); - if (exit == NULL) goto error; + if (exit == NULL) goto out_of_space; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-1] = exit; stack_pointer[0] = res; stack_pointer += 1; @@ -1134,9 +1134,9 @@ _Py_UOpsSymType *exit; _Py_UOpsSymType *res; exit = sym_new_unknown(ctx); - if (exit == NULL) goto error; + if (exit == NULL) goto out_of_space; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-1] = exit; stack_pointer[0] = res; stack_pointer += 1; @@ -1146,7 +1146,7 @@ case _WITH_EXCEPT_START: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[0] = res; stack_pointer += 1; break; @@ -1156,9 +1156,9 @@ _Py_UOpsSymType *prev_exc; _Py_UOpsSymType *new_exc; prev_exc = sym_new_unknown(ctx); - if (prev_exc == NULL) goto error; + if (prev_exc == NULL) goto out_of_space; new_exc = sym_new_unknown(ctx); - if (new_exc == NULL) goto error; + if (new_exc == NULL) goto out_of_space; stack_pointer[-1] = prev_exc; stack_pointer[0] = new_exc; stack_pointer += 1; @@ -1177,9 +1177,9 @@ _Py_UOpsSymType *attr; _Py_UOpsSymType *self = NULL; attr = sym_new_unknown(ctx); - if (attr == NULL) goto error; + if (attr == NULL) goto out_of_space; self = sym_new_unknown(ctx); - if (self == NULL) goto error; + if (self == NULL) goto out_of_space; stack_pointer[-1] = attr; if (1) stack_pointer[0] = self; stack_pointer += ((1) ? 1 : 0); @@ -1190,9 +1190,9 @@ _Py_UOpsSymType *attr; _Py_UOpsSymType *self = NULL; attr = sym_new_unknown(ctx); - if (attr == NULL) goto error; + if (attr == NULL) goto out_of_space; self = sym_new_unknown(ctx); - if (self == NULL) goto error; + if (self == NULL) goto out_of_space; stack_pointer[-1] = attr; if (1) stack_pointer[0] = self; stack_pointer += ((1) ? 1 : 0); @@ -1202,7 +1202,7 @@ case _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: { _Py_UOpsSymType *attr; attr = sym_new_unknown(ctx); - if (attr == NULL) goto error; + if (attr == NULL) goto out_of_space; stack_pointer[-1] = attr; stack_pointer += ((0) ? 1 : 0); break; @@ -1211,7 +1211,7 @@ case _LOAD_ATTR_NONDESCRIPTOR_NO_DICT: { _Py_UOpsSymType *attr; attr = sym_new_unknown(ctx); - if (attr == NULL) goto error; + if (attr == NULL) goto out_of_space; stack_pointer[-1] = attr; stack_pointer += ((0) ? 1 : 0); break; @@ -1225,9 +1225,9 @@ _Py_UOpsSymType *attr; _Py_UOpsSymType *self = NULL; attr = sym_new_unknown(ctx); - if (attr == NULL) goto error; + if (attr == NULL) goto out_of_space; self = sym_new_unknown(ctx); - if (self == NULL) goto error; + if (self == NULL) goto out_of_space; stack_pointer[-1] = attr; if (1) stack_pointer[0] = self; stack_pointer += ((1) ? 1 : 0); @@ -1252,9 +1252,9 @@ _Py_UOpsSymType *func; _Py_UOpsSymType *self; func = sym_new_unknown(ctx); - if (func == NULL) goto error; + if (func == NULL) goto out_of_space; self = sym_new_unknown(ctx); - if (self == NULL) goto error; + if (self == NULL) goto out_of_space; stack_pointer[-2 - oparg] = func; stack_pointer[-1 - oparg] = self; break; @@ -1293,7 +1293,7 @@ assert((inst + 2)->opcode == _PUSH_FRAME); PyFunctionObject *func = (PyFunctionObject *)(inst + 2)->operand; if (func == NULL) { - goto error; + goto out_of_space; } PyCodeObject *co = (PyCodeObject *)func->func_code; assert(self_or_null != NULL); @@ -1314,7 +1314,7 @@ } new_frame = ctx_frame_new(ctx, co, localsplus_start, n_locals_already_filled, 0); if (new_frame == NULL){ - goto error; + goto out_of_space; } stack_pointer[-2 - oparg] = (_Py_UOpsSymType *)new_frame; stack_pointer += -1 - oparg; @@ -1338,7 +1338,7 @@ case _CALL_TYPE_1: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; @@ -1347,7 +1347,7 @@ case _CALL_STR_1: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; @@ -1356,7 +1356,7 @@ case _CALL_TUPLE_1: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; @@ -1372,7 +1372,7 @@ case _CALL_BUILTIN_CLASS: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; @@ -1381,7 +1381,7 @@ case _CALL_BUILTIN_O: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; @@ -1390,7 +1390,7 @@ case _CALL_BUILTIN_FAST: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; @@ -1399,7 +1399,7 @@ case _CALL_BUILTIN_FAST_WITH_KEYWORDS: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; @@ -1408,7 +1408,7 @@ case _CALL_LEN: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; @@ -1417,7 +1417,7 @@ case _CALL_ISINSTANCE: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; @@ -1426,7 +1426,7 @@ case _CALL_METHOD_DESCRIPTOR_O: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; @@ -1435,7 +1435,7 @@ case _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; @@ -1444,7 +1444,7 @@ case _CALL_METHOD_DESCRIPTOR_NOARGS: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; @@ -1453,7 +1453,7 @@ case _CALL_METHOD_DESCRIPTOR_FAST: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; break; @@ -1470,7 +1470,7 @@ case _MAKE_FUNCTION: { _Py_UOpsSymType *func; func = sym_new_unknown(ctx); - if (func == NULL) goto error; + if (func == NULL) goto out_of_space; stack_pointer[-1] = func; break; } @@ -1478,7 +1478,7 @@ case _SET_FUNCTION_ATTRIBUTE: { _Py_UOpsSymType *func; func = sym_new_unknown(ctx); - if (func == NULL) goto error; + if (func == NULL) goto out_of_space; stack_pointer[-2] = func; stack_pointer += -1; break; @@ -1487,7 +1487,7 @@ case _BUILD_SLICE: { _Py_UOpsSymType *slice; slice = sym_new_unknown(ctx); - if (slice == NULL) goto error; + if (slice == NULL) goto out_of_space; stack_pointer[-2 - ((oparg == 3) ? 1 : 0)] = slice; stack_pointer += -1 - ((oparg == 3) ? 1 : 0); break; @@ -1496,7 +1496,7 @@ case _CONVERT_VALUE: { _Py_UOpsSymType *result; result = sym_new_unknown(ctx); - if (result == NULL) goto error; + if (result == NULL) goto out_of_space; stack_pointer[-1] = result; break; } @@ -1504,7 +1504,7 @@ case _FORMAT_SIMPLE: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-1] = res; break; } @@ -1512,7 +1512,7 @@ case _FORMAT_WITH_SPEC: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; break; @@ -1532,7 +1532,7 @@ case _BINARY_OP: { _Py_UOpsSymType *res; res = sym_new_unknown(ctx); - if (res == NULL) goto error; + if (res == NULL) goto out_of_space; stack_pointer[-2] = res; stack_pointer += -1; break; @@ -1607,7 +1607,7 @@ PyObject *ptr = (PyObject *)inst->operand; value = sym_new_const(ctx, ptr); if (value == NULL) { - goto error; + goto out_of_space; } stack_pointer[0] = value; stack_pointer += 1; @@ -1619,7 +1619,7 @@ PyObject *ptr = (PyObject *)inst->operand; value = sym_new_const(ctx, ptr); if (value == NULL) { - goto error; + goto out_of_space; } stack_pointer[0] = value; stack_pointer += 1; @@ -1632,11 +1632,11 @@ PyObject *ptr = (PyObject *)inst->operand; value = sym_new_const(ctx, ptr); if (value == NULL) { - goto error; + goto out_of_space; } null = sym_new_null(ctx); if (null == NULL) { - goto error; + goto out_of_space; } stack_pointer[0] = value; stack_pointer[1] = null; @@ -1650,11 +1650,11 @@ PyObject *ptr = (PyObject *)inst->operand; value = sym_new_const(ctx, ptr); if (value == NULL) { - goto error; + goto out_of_space; } null = sym_new_null(ctx); if (null == NULL) { - goto error; + goto out_of_space; } stack_pointer[0] = value; stack_pointer[1] = null; diff --git a/Tools/cases_generator/tier2_abstract_generator.py b/Tools/cases_generator/tier2_abstract_generator.py index 846c7dda7a348d..e371b4646180f8 100644 --- a/Tools/cases_generator/tier2_abstract_generator.py +++ b/Tools/cases_generator/tier2_abstract_generator.py @@ -88,14 +88,14 @@ def emit_default(out: CWriter, uop: Uop) -> None: if var.is_array(): out.emit(f"for (int _i = {var.size}; --_i >= 0;) {{\n") out.emit(f"{var.name}[_i] = sym_new_unknown(ctx);\n") - out.emit(f"if ({var.name}[_i] == NULL) goto error;\n") + out.emit(f"if ({var.name}[_i] == NULL) goto out_of_space;\n") out.emit("}\n") elif var.name == "null": out.emit(f"{var.name} = sym_new_null(ctx);\n") - out.emit(f"if ({var.name} == NULL) goto error;\n") + out.emit(f"if ({var.name} == NULL) goto out_of_space;\n") else: out.emit(f"{var.name} = sym_new_unknown(ctx);\n") - out.emit(f"if ({var.name} == NULL) goto error;\n") + out.emit(f"if ({var.name} == NULL) goto out_of_space;\n") def write_uop( From cb1d5fea506230cd534063184608055146f4d0f4 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 9 Feb 2024 01:18:15 +0800 Subject: [PATCH 31/52] fix test cases --- Lib/test/test_generated_cases.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index f552ee5a088eff..a7ad6c7320b4ee 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -890,7 +890,7 @@ def test_overridden_abstract_args(self): case OP2: { _Py_UOpsSymType *out; out = sym_new_unknown(ctx); - if (out == NULL) goto error; + if (out == NULL) goto out_of_space; stack_pointer[-1] = out; break; } @@ -915,7 +915,7 @@ def test_no_overridden_case(self): case OP: { _Py_UOpsSymType *out; out = sym_new_unknown(ctx); - if (out == NULL) goto error; + if (out == NULL) goto out_of_space; stack_pointer[-1] = out; break; } From 501302795a212feb19d1bc2f24610204365a42ef Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 9 Feb 2024 01:21:17 +0800 Subject: [PATCH 32/52] remove extra lines --- Python/optimizer.c | 1 - Python/pylifecycle.c | 1 - 2 files changed, 2 deletions(-) diff --git a/Python/optimizer.c b/Python/optimizer.c index b0def4fd10915d..1f5631294030ea 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -221,7 +221,6 @@ static PyMethodDef executor_methods[] = { ///////////////////// Experimental UOp Optimizer ///////////////////// - static void uop_dealloc(_PyExecutorObject *self) { _Py_ExecutorClear(self); diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 6c042425423640..0cac7109340129 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1252,7 +1252,6 @@ init_interp_main(PyThreadState *tstate) if (_Py_get_xoption(&config->xoptions, L"uops") != NULL) { enabled = 1; } - if (enabled) { #else // Always enable tier two for JIT builds (ignoring the environment From 12836605399d05a838bb561e715c41372e3a6ed6 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 9 Feb 2024 01:31:15 +0800 Subject: [PATCH 33/52] fix out_of_space vs error --- Python/tier2_redundancy_eliminator_bytecodes.c | 2 +- Python/tier2_redundancy_eliminator_cases.c.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index 3ea44c4474dfa1..a9bbb83f6bdf27 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -191,7 +191,7 @@ dummy_func(void) { assert((inst + 2)->opcode == _PUSH_FRAME); PyFunctionObject *func = (PyFunctionObject *)(inst + 2)->operand; if (func == NULL) { - goto out_of_space; + goto error; } PyCodeObject *co = (PyCodeObject *)func->func_code; diff --git a/Python/tier2_redundancy_eliminator_cases.c.h b/Python/tier2_redundancy_eliminator_cases.c.h index 4fa721e6043193..c1cd43703dc4b4 100644 --- a/Python/tier2_redundancy_eliminator_cases.c.h +++ b/Python/tier2_redundancy_eliminator_cases.c.h @@ -1293,7 +1293,7 @@ assert((inst + 2)->opcode == _PUSH_FRAME); PyFunctionObject *func = (PyFunctionObject *)(inst + 2)->operand; if (func == NULL) { - goto out_of_space; + goto error; } PyCodeObject *co = (PyCodeObject *)func->func_code; assert(self_or_null != NULL); From d14dac6b896de39019ed427f0206749e9143f24f Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 9 Feb 2024 01:47:46 +0800 Subject: [PATCH 34/52] fix CI --- .../2024-01-16-14-41-54.gh-issue-114058.Cb2b8h.rst | 2 +- Tools/c-analyzer/cpython/_parser.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-01-16-14-41-54.gh-issue-114058.Cb2b8h.rst b/Misc/NEWS.d/next/Core and Builtins/2024-01-16-14-41-54.gh-issue-114058.Cb2b8h.rst index 32d98c1a1a8d0a..beb82dbcd3cccd 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2024-01-16-14-41-54.gh-issue-114058.Cb2b8h.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2024-01-16-14-41-54.gh-issue-114058.Cb2b8h.rst @@ -1 +1 @@ -Enable the tier 2 optimizer for all uops. +Implement the foundations of the Tier 2 redundancy eliminator. diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index d61d605f5f6c95..be89a26058e8e8 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -83,7 +83,7 @@ def clean_lines(text): Python/frozen_modules/*.h Python/generated_cases.c.h Python/executor_cases.c.h -Python/tier2_redundancy_eliminator_bytecodes.c.h +Python/tier2_redundancy_eliminator_cases.c.h # not actually source Python/bytecodes.c From 5394cdde91b05f632ec39003eb5274c7c77f4fca Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 10 Feb 2024 02:29:59 +0800 Subject: [PATCH 35/52] move macros out, remove temp writebuffer --- Include/cpython/pystats.h | 1 - Python/optimizer_analysis.c | 91 ++++++++----------------------------- Python/specialize.c | 2 - 3 files changed, 18 insertions(+), 76 deletions(-) diff --git a/Include/cpython/pystats.h b/Include/cpython/pystats.h index 0537c4702a0717..2e3ee37ba8411e 100644 --- a/Include/cpython/pystats.h +++ b/Include/cpython/pystats.h @@ -124,7 +124,6 @@ typedef struct _optimization_stats { uint64_t optimizer_successes; uint64_t optimizer_failure_reason_null_function; uint64_t optimizer_failure_reason_no_memory; - uint64_t optimizer_failure_reason_no_writebuffer; } OptimizationStats; typedef struct _rare_event_stats { diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 62e88f3e664795..0d64859f082ee5 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -94,12 +94,6 @@ typedef struct frequent_syms { _Py_UOpsSymType *push_nulL_sym; } frequent_syms; -typedef struct uops_emitter { - _PyUOpInstruction *writebuffer; - _PyUOpInstruction *writebuffer_end; - int curr_i; -} uops_emitter; - // Tier 2 types meta interpreter typedef struct _Py_UOpsAbstractInterpContext { PyObject_HEAD @@ -113,8 +107,6 @@ typedef struct _Py_UOpsAbstractInterpContext { frequent_syms frequent_syms; - uops_emitter emitter; - _Py_UOpsSymType **n_consumed; _Py_UOpsSymType **limit; _Py_UOpsSymType *locals_and_stack[MAX_ABSTRACT_INTERP_SIZE]; @@ -187,8 +179,7 @@ abstractcontext_init( _Py_UOpsAbstractInterpContext *ctx, PyCodeObject *co, int curr_stacklen, - int ir_entries, - _PyUOpInstruction *new_writebuffer + int ir_entries ) { ctx->limit = ctx->locals_and_stack + MAX_ABSTRACT_INTERP_SIZE; @@ -215,10 +206,6 @@ abstractcontext_init( // IR and sym setup ctx->frequent_syms.push_nulL_sym = NULL; - // Emitter setup - ctx->emitter.writebuffer = new_writebuffer; - ctx->emitter.curr_i = 0; - ctx->emitter.writebuffer_end = new_writebuffer + ir_entries; return 0; } @@ -379,45 +366,14 @@ op_is_data_movement_only(uint32_t opcode) { opcode == _POP_FRAME); } - -static inline int -emit_i(uops_emitter *emitter, - _PyUOpInstruction inst) -{ - if (emitter->writebuffer + emitter->curr_i >= emitter->writebuffer_end) { - OPT_STAT_INC(optimizer_failure_reason_no_writebuffer); - DPRINTF(1, "out of emission space\n"); - return -1; - } - if (inst.opcode == _NOP) { - return 0; - } - DPRINTF(2, "Emitting instruction at [%d] op: %s, oparg: %d, target: %d, operand: %" PRIu64 " \n", - emitter->curr_i, - _PyOpcode_uop_name[inst.opcode], - inst.oparg, - inst.target, - inst.operand); - emitter->writebuffer[emitter->curr_i] = inst; - emitter->curr_i++; - return 0; -} - -static int -uop_abstract_interpret_single_inst( - _PyUOpInstruction *inst, - _PyUOpInstruction *end, - _Py_UOpsAbstractInterpContext *ctx -) -{ #define STACK_LEVEL() ((int)(stack_pointer - ctx->frame->stack)) #define GETLOCAL(idx) ((ctx->frame->locals[idx])) #define REPLACE_OP(op, arg, oper) \ - new_inst.opcode = op; \ - new_inst.oparg = arg; \ - new_inst.operand = oper; + inst->opcode = op; \ + inst->oparg = arg; \ + inst->operand = oper; #define _LOAD_ATTR_NOT_NULL \ do { \ @@ -431,11 +387,18 @@ uop_abstract_interpret_single_inst( } \ } while (0); +static int +uop_abstract_interpret_single_inst( + _PyUOpInstruction *inst, + _PyUOpInstruction *end, + _Py_UOpsAbstractInterpContext *ctx +) +{ + int oparg = inst->oparg; uint32_t opcode = inst->opcode; _Py_UOpsSymType **stack_pointer = ctx->frame->stack_pointer; - _PyUOpInstruction new_inst = *inst; DPRINTF(3, "Abstract interpreting %s:%d ", _PyOpcode_uop_name[opcode], @@ -452,17 +415,11 @@ uop_abstract_interpret_single_inst( ctx->frame->stack_pointer = stack_pointer; assert(STACK_LEVEL() >= 0); - if (emit_i(&ctx->emitter, new_inst) < 0) { - goto error; - } return 0; out_of_space: DPRINTF(1, "Out of space in abstract interpreter\n"); - if (emit_i(&ctx->emitter, new_inst) < 0) { - goto error; - } return 0; error: DPRINTF(1, "Encountered error in abstract interpreter\n"); @@ -678,7 +635,6 @@ static int uop_redundancy_eliminator( PyCodeObject *co, _PyUOpInstruction *trace, - _PyUOpInstruction *new_trace, int trace_len, int curr_stacklen ) @@ -689,13 +645,12 @@ uop_redundancy_eliminator( if (abstractcontext_init( &ctx, co, curr_stacklen, - trace_len, new_trace) < 0) { + trace_len) < 0) { goto error; } _PyUOpInstruction *curr = NULL; _PyUOpInstruction *end = NULL; int status = 0; - int res = 0; curr = trace; end = trace + trace_len; @@ -715,14 +670,9 @@ uop_redundancy_eliminator( assert(op_is_end(curr->opcode)); - if (emit_i(&ctx.emitter, *curr) < 0) { - goto error; - } - - res = ctx.emitter.curr_i; abstractcontext_fini(&ctx); - return res; + return 0; error: abstractcontext_fini(&ctx); @@ -824,7 +774,6 @@ _Py_uop_analyze_and_optimize( ) { OPT_STAT_INC(optimizer_attempts); - _PyUOpInstruction temp_writebuffer[UOP_MAX_TRACE_LENGTH]; int err = remove_globals(frame, buffer, buffer_size, dependencies); if (err <= 0) { @@ -833,21 +782,17 @@ _Py_uop_analyze_and_optimize( peephole_opt(frame, buffer, buffer_size); - int new_trace_len = uop_redundancy_eliminator( - (PyCodeObject *)frame->f_executable, buffer, temp_writebuffer, + err = uop_redundancy_eliminator( + (PyCodeObject *)frame->f_executable, buffer, buffer_size, curr_stacklen); - if (new_trace_len < 0) { + if (err < 0) { goto error; } - remove_unneeded_uops(temp_writebuffer, new_trace_len); - - // Fill in our new trace! - memcpy(buffer, temp_writebuffer, new_trace_len * sizeof(_PyUOpInstruction)); - + remove_unneeded_uops(buffer, buffer_size); OPT_STAT_INC(optimizer_successes); return 1; diff --git a/Python/specialize.c b/Python/specialize.c index 1704262018854e..ddfdfc5f2ea45c 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -246,8 +246,6 @@ print_optimization_stats(FILE *out, OptimizationStats *stats) stats->optimizer_failure_reason_null_function); fprintf(out, "Optimization optimizer failure no memory: %" PRIu64 "\n", stats->optimizer_failure_reason_no_memory); - fprintf(out, "Optimization optimizer failure no writebuffer left: %" PRIu64 "\n", - stats->optimizer_failure_reason_no_writebuffer); const char* const* names; for (int i = 0; i < 512; i++) { From 072977873bb4ec66b165697dfe53b119a206207b Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 11 Feb 2024 05:50:19 +0800 Subject: [PATCH 36/52] update comment --- Python/optimizer_analysis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 0d64859f082ee5..2785df08b09b06 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -226,7 +226,7 @@ ctx_frame_pop( } -// Steals a reference to const_val +// Takes a borrowed reference to const_val, turns that into a strong reference. static _Py_UOpsSymType* _Py_UOpsSymType_New(_Py_UOpsAbstractInterpContext *ctx, PyObject *const_val) From 35227f8ff9a9bcd5638546be5f67c66bed965b15 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 12 Feb 2024 18:57:24 +0800 Subject: [PATCH 37/52] Address review --- Python/optimizer_analysis.c | 28 +++++++++---------- .../tier2_redundancy_eliminator_bytecodes.c | 28 +++++++++---------- Python/tier2_redundancy_eliminator_cases.c.h | 28 +++++++++---------- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 2785df08b09b06..2a2154b1b51e4b 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -1,12 +1,12 @@ /* - * This file contains the optimizer for CPython uops. + * This file contains the support code for CPython's uops redundancy eliminator. + * It also performs some simple optimizations. * It performs a traditional data-flow analysis[1] over the trace of uops. * Using the information gained, it chooses to emit, or skip certain instructions * if possible. * - * [1] For information on data-flow analysis, please see page 27 onwards in - * https://ilyasergey.net/CS4212/_static/lectures/PLDI-Week-12-dataflow.pdf - * Credits to the courses UPenn Compilers (CIS 341) and NUS Compiler Design (CS4212). + * [1] For information on data-flow analysis, please see + * https://clang.llvm.org/docs/DataFlowAnalysisIntro.html * * */ #include "Python.h" @@ -228,7 +228,7 @@ ctx_frame_pop( // Takes a borrowed reference to const_val, turns that into a strong reference. static _Py_UOpsSymType* -_Py_UOpsSymType_New(_Py_UOpsAbstractInterpContext *ctx, +sym_new(_Py_UOpsAbstractInterpContext *ctx, PyObject *const_val) { _Py_UOpsSymType *self = &ctx->t_arena.arena[ctx->t_arena.ty_curr_number]; @@ -262,7 +262,7 @@ sym_has_flag(_Py_UOpsSymType *sym, int flag) } static inline void -sym_set_pytype(_Py_UOpsSymType *sym, PyTypeObject *tp) +sym_set_type(_Py_UOpsSymType *sym, PyTypeObject *tp) { assert(tp == NULL || PyType_Check(tp)); sym->typ = tp; @@ -273,7 +273,7 @@ sym_set_pytype(_Py_UOpsSymType *sym, PyTypeObject *tp) static inline _Py_UOpsSymType* sym_new_unknown(_Py_UOpsAbstractInterpContext *ctx) { - return _Py_UOpsSymType_New(ctx,NULL); + return sym_new(ctx,NULL); } static inline _Py_UOpsSymType* @@ -288,14 +288,14 @@ sym_new_known_notnull(_Py_UOpsAbstractInterpContext *ctx) } static inline _Py_UOpsSymType* -sym_new_known_pytype(_Py_UOpsAbstractInterpContext *ctx, +sym_new_known_type(_Py_UOpsAbstractInterpContext *ctx, PyTypeObject *typ) { - _Py_UOpsSymType *res = _Py_UOpsSymType_New(ctx,NULL); + _Py_UOpsSymType *res = sym_new(ctx,NULL); if (res == NULL) { return NULL; } - sym_set_pytype(res, typ); + sym_set_type(res, typ); return res; } @@ -304,14 +304,14 @@ static inline _Py_UOpsSymType* sym_new_const(_Py_UOpsAbstractInterpContext *ctx, PyObject *const_val) { assert(const_val != NULL); - _Py_UOpsSymType *temp = _Py_UOpsSymType_New( + _Py_UOpsSymType *temp = sym_new( ctx, const_val ); if (temp == NULL) { return NULL; } - sym_set_pytype(temp, Py_TYPE(const_val)); + sym_set_type(temp, Py_TYPE(const_val)); sym_set_flag(temp, TRUE_CONST); return temp; } @@ -326,14 +326,14 @@ sym_new_null(_Py_UOpsAbstractInterpContext *ctx) if (null_sym == NULL) { return NULL; } - sym_set_pytype(null_sym, NULL); + sym_set_type(null_sym, NULL); ctx->frequent_syms.push_nulL_sym = null_sym; return null_sym; } static inline bool -sym_matches_pytype(_Py_UOpsSymType *sym, PyTypeObject *typ) +sym_matches_type(_Py_UOpsSymType *sym, PyTypeObject *typ) { assert(typ == NULL || PyType_Check(typ)); if (!sym_has_flag(sym, KNOWN_TYPE)) { diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index a9bbb83f6bdf27..bca659d215f491 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -32,7 +32,7 @@ dummy_func(void) { op(_LOAD_FAST_CHECK, (-- value)) { value = GETLOCAL(oparg); // We guarantee this will error - just bail and don't optimize it. - if (sym_matches_pytype(value, NULL)) { + if (sym_matches_type(value, NULL)) { goto out_of_space; } } @@ -62,21 +62,21 @@ dummy_func(void) { } op(_GUARD_BOTH_INT, (left, right -- left, right)) { - if (sym_matches_pytype(left, &PyLong_Type) && - sym_matches_pytype(right, &PyLong_Type)) { + if (sym_matches_type(left, &PyLong_Type) && + sym_matches_type(right, &PyLong_Type)) { REPLACE_OP(_NOP, 0, 0); } - sym_set_pytype(left, &PyLong_Type); - sym_set_pytype(right, &PyLong_Type); + sym_set_type(left, &PyLong_Type); + sym_set_type(right, &PyLong_Type); } op(_GUARD_BOTH_FLOAT, (left, right -- left, right)) { - if (sym_matches_pytype(left, &PyFloat_Type) && - sym_matches_pytype(right, &PyFloat_Type)) { + if (sym_matches_type(left, &PyFloat_Type) && + sym_matches_type(right, &PyFloat_Type)) { REPLACE_OP(_NOP, 0 ,0); } - sym_set_pytype(left, &PyFloat_Type); - sym_set_pytype(right, &PyFloat_Type); + sym_set_type(left, &PyFloat_Type); + sym_set_type(right, &PyFloat_Type); } @@ -84,7 +84,7 @@ dummy_func(void) { // TODO constant propagation (void)left; (void)right; - res = sym_new_known_pytype(ctx, &PyLong_Type); + res = sym_new_known_type(ctx, &PyLong_Type); if (res == NULL) { goto out_of_space; } @@ -173,14 +173,14 @@ dummy_func(void) { } op(_CHECK_FUNCTION_EXACT_ARGS, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { - sym_set_pytype(callable, &PyFunction_Type); + sym_set_type(callable, &PyFunction_Type); (void)self_or_null; (void)func_version; } op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- callable, null, unused[oparg])) { - sym_set_pytype(null, NULL); - sym_set_pytype(callable, &PyMethod_Type); + sym_set_type(null, NULL); + sym_set_type(callable, &PyMethod_Type); } op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null, args[oparg] -- new_frame: _Py_UOpsAbstractFrame *)) { @@ -258,7 +258,7 @@ dummy_func(void) { } op(_ITER_NEXT_RANGE, (iter -- iter, next)) { - next = sym_new_known_pytype(ctx, &PyLong_Type); + next = sym_new_known_type(ctx, &PyLong_Type); if (next == NULL) { goto out_of_space; } diff --git a/Python/tier2_redundancy_eliminator_cases.c.h b/Python/tier2_redundancy_eliminator_cases.c.h index c1cd43703dc4b4..73095f9862030b 100644 --- a/Python/tier2_redundancy_eliminator_cases.c.h +++ b/Python/tier2_redundancy_eliminator_cases.c.h @@ -17,7 +17,7 @@ _Py_UOpsSymType *value; value = GETLOCAL(oparg); // We guarantee this will error - just bail and don't optimize it. - if (sym_matches_pytype(value, NULL)) { + if (sym_matches_type(value, NULL)) { goto out_of_space; } stack_pointer[0] = value; @@ -170,12 +170,12 @@ _Py_UOpsSymType *left; right = stack_pointer[-1]; left = stack_pointer[-2]; - if (sym_matches_pytype(left, &PyLong_Type) && - sym_matches_pytype(right, &PyLong_Type)) { + if (sym_matches_type(left, &PyLong_Type) && + sym_matches_type(right, &PyLong_Type)) { REPLACE_OP(_NOP, 0, 0); } - sym_set_pytype(left, &PyLong_Type); - sym_set_pytype(right, &PyLong_Type); + sym_set_type(left, &PyLong_Type); + sym_set_type(right, &PyLong_Type); break; } @@ -197,7 +197,7 @@ // TODO constant propagation (void)left; (void)right; - res = sym_new_known_pytype(ctx, &PyLong_Type); + res = sym_new_known_type(ctx, &PyLong_Type); if (res == NULL) { goto out_of_space; } @@ -220,12 +220,12 @@ _Py_UOpsSymType *left; right = stack_pointer[-1]; left = stack_pointer[-2]; - if (sym_matches_pytype(left, &PyFloat_Type) && - sym_matches_pytype(right, &PyFloat_Type)) { + if (sym_matches_type(left, &PyFloat_Type) && + sym_matches_type(right, &PyFloat_Type)) { REPLACE_OP(_NOP, 0 ,0); } - sym_set_pytype(left, &PyFloat_Type); - sym_set_pytype(right, &PyFloat_Type); + sym_set_type(left, &PyFloat_Type); + sym_set_type(right, &PyFloat_Type); break; } @@ -1105,7 +1105,7 @@ _Py_UOpsSymType *iter; _Py_UOpsSymType *next; iter = stack_pointer[-1]; - next = sym_new_known_pytype(ctx, &PyLong_Type); + next = sym_new_known_type(ctx, &PyLong_Type); if (next == NULL) { goto out_of_space; } @@ -1243,8 +1243,8 @@ _Py_UOpsSymType *callable; null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - sym_set_pytype(null, NULL); - sym_set_pytype(callable, &PyMethod_Type); + sym_set_type(null, NULL); + sym_set_type(callable, &PyMethod_Type); break; } @@ -1270,7 +1270,7 @@ self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; uint32_t func_version = (uint32_t)inst->operand; - sym_set_pytype(callable, &PyFunction_Type); + sym_set_type(callable, &PyFunction_Type); (void)self_or_null; (void)func_version; break; From 40a19f7305b3c0f026123290ae16ea94b35911ad Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 12 Feb 2024 19:44:47 +0800 Subject: [PATCH 38/52] set IS_NULL as a flag --- Python/optimizer_analysis.c | 18 ++++++++++++++++-- Python/tier2_redundancy_eliminator_bytecodes.c | 4 ++-- Python/tier2_redundancy_eliminator_cases.c.h | 4 ++-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 2a2154b1b51e4b..4b2e277413d49f 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -63,7 +63,8 @@ // Flags for below. #define KNOWN_TYPE 1 << 0 // Just to differentiate NULL in typ #define TRUE_CONST 1 << 1 -#define NOT_NULL 1 << 2 +#define IS_NULL 1 << 2 +#define NOT_NULL 1 << 3 typedef struct { int flags; @@ -255,6 +256,12 @@ sym_set_flag(_Py_UOpsSymType *sym, int flag) sym->flags |= flag; } +static inline void +sym_clear_flag(_Py_UOpsSymType *sym, int flag) +{ + sym->flags &= (~flag); +} + static inline bool sym_has_flag(_Py_UOpsSymType *sym, int flag) { @@ -269,6 +276,13 @@ sym_set_type(_Py_UOpsSymType *sym, PyTypeObject *tp) sym_set_flag(sym, KNOWN_TYPE); } +static inline void +sym_set_null(_Py_UOpsSymType *sym) +{ + sym_set_flag(sym, IS_NULL); + sym_clear_flag(sym, NOT_NULL); +} + static inline _Py_UOpsSymType* sym_new_unknown(_Py_UOpsAbstractInterpContext *ctx) @@ -326,7 +340,7 @@ sym_new_null(_Py_UOpsAbstractInterpContext *ctx) if (null_sym == NULL) { return NULL; } - sym_set_type(null_sym, NULL); + sym_set_null(null_sym); ctx->frequent_syms.push_nulL_sym = null_sym; return null_sym; } diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index bca659d215f491..57e5f241261d85 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -32,7 +32,7 @@ dummy_func(void) { op(_LOAD_FAST_CHECK, (-- value)) { value = GETLOCAL(oparg); // We guarantee this will error - just bail and don't optimize it. - if (sym_matches_type(value, NULL)) { + if (sym_has_flag(value, IS_NULL)) { goto out_of_space; } } @@ -179,7 +179,7 @@ dummy_func(void) { } op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- callable, null, unused[oparg])) { - sym_set_type(null, NULL); + sym_set_null(null); sym_set_type(callable, &PyMethod_Type); } diff --git a/Python/tier2_redundancy_eliminator_cases.c.h b/Python/tier2_redundancy_eliminator_cases.c.h index 73095f9862030b..715089fa9ede9e 100644 --- a/Python/tier2_redundancy_eliminator_cases.c.h +++ b/Python/tier2_redundancy_eliminator_cases.c.h @@ -17,7 +17,7 @@ _Py_UOpsSymType *value; value = GETLOCAL(oparg); // We guarantee this will error - just bail and don't optimize it. - if (sym_matches_type(value, NULL)) { + if (sym_has_flag(value, IS_NULL)) { goto out_of_space; } stack_pointer[0] = value; @@ -1243,7 +1243,7 @@ _Py_UOpsSymType *callable; null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - sym_set_type(null, NULL); + sym_set_null(null); sym_set_type(callable, &PyMethod_Type); break; } From aaeb4cdecb918fb43419d017dfa6376099f186e8 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 12 Feb 2024 20:02:07 +0800 Subject: [PATCH 39/52] Fix a bug --- Python/pylifecycle.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 61c9d4f9ea9575..5eb2b085230491 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1252,6 +1252,7 @@ init_interp_main(PyThreadState *tstate) if (_Py_get_xoption(&config->xoptions, L"uops") != NULL) { enabled = 1; } + enabled = 1; if (enabled) { #else // Always enable tier two for JIT builds (ignoring the environment From 61432567039c349f54c78ae3bcf963d76b3eff5b Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 12 Feb 2024 20:02:31 +0800 Subject: [PATCH 40/52] fix a bug in frames --- Python/optimizer_analysis.c | 1 + Python/pylifecycle.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 4b2e277413d49f..9650313fd86a2a 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -280,6 +280,7 @@ static inline void sym_set_null(_Py_UOpsSymType *sym) { sym_set_flag(sym, IS_NULL); + sym_set_flag(sym, KNOWN_TYPE); sym_clear_flag(sym, NOT_NULL); } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 5eb2b085230491..61c9d4f9ea9575 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1252,7 +1252,6 @@ init_interp_main(PyThreadState *tstate) if (_Py_get_xoption(&config->xoptions, L"uops") != NULL) { enabled = 1; } - enabled = 1; if (enabled) { #else // Always enable tier two for JIT builds (ignoring the environment From 35fff8f8304774a7b714bdc1b8a164c0a98e5634 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 13 Feb 2024 00:38:29 +0800 Subject: [PATCH 41/52] address review --- Python/optimizer_analysis.c | 35 ++++++++++--------- .../tier2_redundancy_eliminator_bytecodes.c | 6 ++-- Python/tier2_redundancy_eliminator_cases.c.h | 6 ++-- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 9650313fd86a2a..05b9db2c81f220 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -268,6 +268,24 @@ sym_has_flag(_Py_UOpsSymType *sym, int flag) return (sym->flags & flag) != 0; } +static inline bool +sym_is_known_type(_Py_UOpsSymType *sym) +{ + return sym_has_flag(sym, KNOWN_TYPE); +} + +static inline bool +sym_is_not_null(_Py_UOpsSymType *sym) +{ + return sym_has_flag(sym, NOT_NULL); +} + +static inline bool +sym_is_null(_Py_UOpsSymType *sym) +{ + return sym_has_flag(sym, IS_NULL); +} + static inline void sym_set_type(_Py_UOpsSymType *sym, PyTypeObject *tp) { @@ -364,23 +382,6 @@ op_is_end(uint32_t opcode) return opcode == _EXIT_TRACE || opcode == _JUMP_TO_TOP; } - -static inline bool -op_is_bookkeeping(uint32_t opcode) { - return (opcode == _SET_IP || - opcode == _CHECK_VALIDITY || - opcode == _SAVE_RETURN_OFFSET || - opcode == _RESUME_CHECK); -} - -static inline bool -op_is_data_movement_only(uint32_t opcode) { - return (opcode == _STORE_FAST || - opcode == STORE_FAST_MAYBE_NULL || - opcode == _PUSH_FRAME || - opcode == _POP_FRAME); -} - #define STACK_LEVEL() ((int)(stack_pointer - ctx->frame->stack)) #define GETLOCAL(idx) ((ctx->frame->locals[idx])) diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index 57e5f241261d85..22d01259e2cac4 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -32,7 +32,7 @@ dummy_func(void) { op(_LOAD_FAST_CHECK, (-- value)) { value = GETLOCAL(oparg); // We guarantee this will error - just bail and don't optimize it. - if (sym_has_flag(value, IS_NULL)) { + if (sym_is_null(value)) { goto out_of_space; } } @@ -197,7 +197,7 @@ dummy_func(void) { assert(self_or_null != NULL); assert(args != NULL); - if (sym_has_flag(self_or_null, NOT_NULL)) { + if (sym_is_not_null(self_or_null)) { // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in VM args--; argcount++; @@ -208,7 +208,7 @@ dummy_func(void) { // Can determine statically, so we interleave the new locals // and make the current stack the new locals. // This also sets up for true call inlining. - if (sym_has_flag(self_or_null, KNOWN_TYPE)) { + if (sym_is_known_type(self_or_null)) { localsplus_start = args; n_locals_already_filled = argcount; } diff --git a/Python/tier2_redundancy_eliminator_cases.c.h b/Python/tier2_redundancy_eliminator_cases.c.h index 715089fa9ede9e..f6d39601efd85b 100644 --- a/Python/tier2_redundancy_eliminator_cases.c.h +++ b/Python/tier2_redundancy_eliminator_cases.c.h @@ -17,7 +17,7 @@ _Py_UOpsSymType *value; value = GETLOCAL(oparg); // We guarantee this will error - just bail and don't optimize it. - if (sym_has_flag(value, IS_NULL)) { + if (sym_is_null(value)) { goto out_of_space; } stack_pointer[0] = value; @@ -1298,7 +1298,7 @@ PyCodeObject *co = (PyCodeObject *)func->func_code; assert(self_or_null != NULL); assert(args != NULL); - if (sym_has_flag(self_or_null, NOT_NULL)) { + if (sym_is_not_null(self_or_null)) { // Bound method fiddling, same as _INIT_CALL_PY_EXACT_ARGS in VM args--; argcount++; @@ -1308,7 +1308,7 @@ // Can determine statically, so we interleave the new locals // and make the current stack the new locals. // This also sets up for true call inlining. - if (sym_has_flag(self_or_null, KNOWN_TYPE)) { + if (sym_is_known_type(self_or_null)) { localsplus_start = args; n_locals_already_filled = argcount; } From 2b6eff45f2e76fe5797854abd193030a62072d80 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 13 Feb 2024 00:39:55 +0800 Subject: [PATCH 42/52] remove sym sharing --- Python/optimizer_analysis.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 05b9db2c81f220..3cceb0e16cc519 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -91,10 +91,6 @@ typedef struct ty_arena { _Py_UOpsSymType arena[TY_ARENA_SIZE]; } ty_arena; -typedef struct frequent_syms { - _Py_UOpsSymType *push_nulL_sym; -} frequent_syms; - // Tier 2 types meta interpreter typedef struct _Py_UOpsAbstractInterpContext { PyObject_HEAD @@ -106,8 +102,6 @@ typedef struct _Py_UOpsAbstractInterpContext { // Arena for the symbolic types. ty_arena t_arena; - frequent_syms frequent_syms; - _Py_UOpsSymType **n_consumed; _Py_UOpsSymType **limit; _Py_UOpsSymType *locals_and_stack[MAX_ABSTRACT_INTERP_SIZE]; @@ -203,10 +197,6 @@ abstractcontext_init( } ctx->curr_frame_depth++; ctx->frame = frame; - - // IR and sym setup - ctx->frequent_syms.push_nulL_sym = NULL; - return 0; } @@ -352,15 +342,11 @@ sym_new_const(_Py_UOpsAbstractInterpContext *ctx, PyObject *const_val) static _Py_UOpsSymType* sym_new_null(_Py_UOpsAbstractInterpContext *ctx) { - if (ctx->frequent_syms.push_nulL_sym != NULL) { - return ctx->frequent_syms.push_nulL_sym; - } _Py_UOpsSymType *null_sym = sym_new_unknown(ctx); if (null_sym == NULL) { return NULL; } sym_set_null(null_sym); - ctx->frequent_syms.push_nulL_sym = null_sym; return null_sym; } From 3b5b498d6ec911fe91be2297c6fb0857b95a24d4 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 13 Feb 2024 00:52:12 +0800 Subject: [PATCH 43/52] Address changes --- Python/optimizer_analysis.c | 17 ++++++++--------- Python/tier2_redundancy_eliminator_bytecodes.c | 2 +- Python/tier2_redundancy_eliminator_cases.c.h | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 3cceb0e16cc519..ebc74296f2f302 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -61,7 +61,7 @@ // Flags for below. -#define KNOWN_TYPE 1 << 0 // Just to differentiate NULL in typ +#define KNOWN 1 << 0 #define TRUE_CONST 1 << 1 #define IS_NULL 1 << 2 #define NOT_NULL 1 << 3 @@ -259,21 +259,21 @@ sym_has_flag(_Py_UOpsSymType *sym, int flag) } static inline bool -sym_is_known_type(_Py_UOpsSymType *sym) +sym_is_known(_Py_UOpsSymType *sym) { - return sym_has_flag(sym, KNOWN_TYPE); + return sym_has_flag(sym, KNOWN); } static inline bool sym_is_not_null(_Py_UOpsSymType *sym) { - return sym_has_flag(sym, NOT_NULL); + return (sym->flags & (IS_NULL | NOT_NULL)) == NOT_NULL; } static inline bool sym_is_null(_Py_UOpsSymType *sym) { - return sym_has_flag(sym, IS_NULL); + return (sym->flags & (IS_NULL | NOT_NULL)) == IS_NULL; } static inline void @@ -281,15 +281,14 @@ sym_set_type(_Py_UOpsSymType *sym, PyTypeObject *tp) { assert(tp == NULL || PyType_Check(tp)); sym->typ = tp; - sym_set_flag(sym, KNOWN_TYPE); + sym_set_flag(sym, KNOWN); } static inline void sym_set_null(_Py_UOpsSymType *sym) { sym_set_flag(sym, IS_NULL); - sym_set_flag(sym, KNOWN_TYPE); - sym_clear_flag(sym, NOT_NULL); + sym_set_flag(sym, KNOWN); } @@ -355,7 +354,7 @@ static inline bool sym_matches_type(_Py_UOpsSymType *sym, PyTypeObject *typ) { assert(typ == NULL || PyType_Check(typ)); - if (!sym_has_flag(sym, KNOWN_TYPE)) { + if (!sym_has_flag(sym, KNOWN)) { return false; } return sym->typ == typ; diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index 22d01259e2cac4..ed490a99c423a8 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -208,7 +208,7 @@ dummy_func(void) { // Can determine statically, so we interleave the new locals // and make the current stack the new locals. // This also sets up for true call inlining. - if (sym_is_known_type(self_or_null)) { + if (sym_is_known(self_or_null)) { localsplus_start = args; n_locals_already_filled = argcount; } diff --git a/Python/tier2_redundancy_eliminator_cases.c.h b/Python/tier2_redundancy_eliminator_cases.c.h index f6d39601efd85b..b1379ae4412342 100644 --- a/Python/tier2_redundancy_eliminator_cases.c.h +++ b/Python/tier2_redundancy_eliminator_cases.c.h @@ -1308,7 +1308,7 @@ // Can determine statically, so we interleave the new locals // and make the current stack the new locals. // This also sets up for true call inlining. - if (sym_is_known_type(self_or_null)) { + if (sym_is_known(self_or_null)) { localsplus_start = args; n_locals_already_filled = argcount; } From 702a6fc41cc780779ad106d65c8f1462e681c16a Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 13 Feb 2024 01:11:23 +0800 Subject: [PATCH 44/52] Address review --- Python/optimizer_analysis.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index ebc74296f2f302..daec7e01fd8eaf 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -279,9 +279,10 @@ sym_is_null(_Py_UOpsSymType *sym) static inline void sym_set_type(_Py_UOpsSymType *sym, PyTypeObject *tp) { - assert(tp == NULL || PyType_Check(tp)); + assert(PyType_Check(tp)); sym->typ = tp; sym_set_flag(sym, KNOWN); + sym_set_flag(sym, NOT_NULL); } static inline void @@ -335,6 +336,8 @@ sym_new_const(_Py_UOpsAbstractInterpContext *ctx, PyObject *const_val) } sym_set_type(temp, Py_TYPE(const_val)); sym_set_flag(temp, TRUE_CONST); + sym_set_flag(temp, KNOWN); + sym_set_flag(temp, NOT_NULL); return temp; } From 77e56ffd5659380052396a23908b60b25b609cae Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 13 Feb 2024 19:01:03 +0800 Subject: [PATCH 45/52] address review --- Include/cpython/pystats.h | 1 - Python/optimizer_analysis.c | 137 +++++++----------- Python/pylifecycle.c | 1 + Python/specialize.c | 2 - .../tier2_redundancy_eliminator_bytecodes.c | 4 +- Python/tier2_redundancy_eliminator_cases.c.h | 4 +- 6 files changed, 59 insertions(+), 90 deletions(-) diff --git a/Include/cpython/pystats.h b/Include/cpython/pystats.h index 2e3ee37ba8411e..77d97a763cbfdf 100644 --- a/Include/cpython/pystats.h +++ b/Include/cpython/pystats.h @@ -122,7 +122,6 @@ typedef struct _optimization_stats { uint64_t optimized_trace_length_hist[_Py_UOP_HIST_SIZE]; uint64_t optimizer_attempts; uint64_t optimizer_successes; - uint64_t optimizer_failure_reason_null_function; uint64_t optimizer_failure_reason_no_memory; } OptimizationStats; diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index daec7e01fd8eaf..768a1de2514e22 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -370,69 +370,6 @@ op_is_end(uint32_t opcode) return opcode == _EXIT_TRACE || opcode == _JUMP_TO_TOP; } -#define STACK_LEVEL() ((int)(stack_pointer - ctx->frame->stack)) - -#define GETLOCAL(idx) ((ctx->frame->locals[idx])) - -#define REPLACE_OP(op, arg, oper) \ - inst->opcode = op; \ - inst->oparg = arg; \ - inst->operand = oper; - -#define _LOAD_ATTR_NOT_NULL \ - do { \ - attr = sym_new_known_notnull(ctx); \ - if (attr == NULL) { \ - goto error; \ - } \ - null = sym_new_null(ctx); \ - if (null == NULL) { \ - goto error; \ - } \ - } while (0); - -static int -uop_abstract_interpret_single_inst( - _PyUOpInstruction *inst, - _PyUOpInstruction *end, - _Py_UOpsAbstractInterpContext *ctx -) -{ - - int oparg = inst->oparg; - uint32_t opcode = inst->opcode; - - _Py_UOpsSymType **stack_pointer = ctx->frame->stack_pointer; - - DPRINTF(3, "Abstract interpreting %s:%d ", - _PyOpcode_uop_name[opcode], - oparg); - switch (opcode) { -#include "tier2_redundancy_eliminator_cases.c.h" - - default: - DPRINTF(1, "Unknown opcode in abstract interpreter\n"); - Py_UNREACHABLE(); - } - assert(ctx->frame != NULL); - DPRINTF(3, " stack_level %d\n", STACK_LEVEL()); - ctx->frame->stack_pointer = stack_pointer; - assert(STACK_LEVEL() >= 0); - - - return 0; - -out_of_space: - DPRINTF(1, "Out of space in abstract interpreter\n"); - return 0; -error: - DPRINTF(1, "Encountered error in abstract interpreter\n"); - return -1; - -} - - - static int get_mutations(PyObject* dict) { assert(PyDict_CheckExact(dict)); @@ -635,6 +572,30 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, return 0; } + + +#define STACK_LEVEL() ((int)(stack_pointer - ctx->frame->stack)) + +#define GETLOCAL(idx) ((ctx->frame->locals[idx])) + +#define REPLACE_OP(INST, OP, ARG, OPERAND) \ + INST->opcode = OP; \ + INST->oparg = ARG; \ + INST->operand = OPERAND; + +#define _LOAD_ATTR_NOT_NULL \ + do { \ + attr = sym_new_known_notnull(ctx); \ + if (attr == NULL) { \ + goto error; \ + } \ + null = sym_new_null(ctx); \ + if (null == NULL) { \ + goto error; \ + } \ + } while (0); + + static int uop_redundancy_eliminator( PyCodeObject *co, @@ -644,42 +605,52 @@ uop_redundancy_eliminator( ) { - _Py_UOpsAbstractInterpContext ctx; + _Py_UOpsAbstractInterpContext context; + _Py_UOpsAbstractInterpContext *ctx = &context; if (abstractcontext_init( - &ctx, + ctx, co, curr_stacklen, trace_len) < 0) { goto error; } - _PyUOpInstruction *curr = NULL; - _PyUOpInstruction *end = NULL; - int status = 0; - curr = trace; - end = trace + trace_len; - ; - while (curr < end && !op_is_end(curr->opcode)) { + for (_PyUOpInstruction *inst = trace; + inst < trace + trace_len && !op_is_end(inst->opcode); + inst++) { - status = uop_abstract_interpret_single_inst( - curr, end, &ctx - ); - if (status == -1) { - goto error; - } + int oparg = inst->oparg; + uint32_t opcode = inst->opcode; - curr++; + _Py_UOpsSymType **stack_pointer = ctx->frame->stack_pointer; - } + DPRINTF(3, "Abstract interpreting %s:%d ", + _PyOpcode_uop_name[opcode], + oparg); + switch (opcode) { +#include "tier2_redundancy_eliminator_cases.c.h" + + default: + DPRINTF(1, "Unknown opcode in abstract interpreter\n"); + Py_UNREACHABLE(); + } + assert(ctx->frame != NULL); + DPRINTF(3, " stack_level %d\n", STACK_LEVEL()); + ctx->frame->stack_pointer = stack_pointer; + assert(STACK_LEVEL() >= 0); + continue; - assert(op_is_end(curr->opcode)); + out_of_space: + DPRINTF(1, "Out of space in abstract interpreter\n"); + } - abstractcontext_fini(&ctx); + abstractcontext_fini(ctx); return 0; error: - abstractcontext_fini(&ctx); + DPRINTF(1, "Encountered error in abstract interpreter\n"); + abstractcontext_fini(ctx); return -1; } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 61c9d4f9ea9575..5eb2b085230491 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1252,6 +1252,7 @@ init_interp_main(PyThreadState *tstate) if (_Py_get_xoption(&config->xoptions, L"uops") != NULL) { enabled = 1; } + enabled = 1; if (enabled) { #else // Always enable tier two for JIT builds (ignoring the environment diff --git a/Python/specialize.c b/Python/specialize.c index ddfdfc5f2ea45c..cd0778bb315986 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -242,8 +242,6 @@ print_optimization_stats(FILE *out, OptimizationStats *stats) fprintf(out, "Optimization optimizer attempts: %" PRIu64 "\n", stats->optimizer_attempts); fprintf(out, "Optimization optimizer successes: %" PRIu64 "\n", stats->optimizer_successes); - fprintf(out, "Optimization optimizer failure null function: %" PRIu64 "\n", - stats->optimizer_failure_reason_null_function); fprintf(out, "Optimization optimizer failure no memory: %" PRIu64 "\n", stats->optimizer_failure_reason_no_memory); diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index ed490a99c423a8..5d9e8f12ef8140 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -64,7 +64,7 @@ dummy_func(void) { op(_GUARD_BOTH_INT, (left, right -- left, right)) { if (sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type)) { - REPLACE_OP(_NOP, 0, 0); + REPLACE_OP(inst, _NOP, 0, 0); } sym_set_type(left, &PyLong_Type); sym_set_type(right, &PyLong_Type); @@ -73,7 +73,7 @@ dummy_func(void) { op(_GUARD_BOTH_FLOAT, (left, right -- left, right)) { if (sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type)) { - REPLACE_OP(_NOP, 0 ,0); + REPLACE_OP(inst, _NOP, 0 ,0); } sym_set_type(left, &PyFloat_Type); sym_set_type(right, &PyFloat_Type); diff --git a/Python/tier2_redundancy_eliminator_cases.c.h b/Python/tier2_redundancy_eliminator_cases.c.h index b1379ae4412342..84295f64a70ff9 100644 --- a/Python/tier2_redundancy_eliminator_cases.c.h +++ b/Python/tier2_redundancy_eliminator_cases.c.h @@ -172,7 +172,7 @@ left = stack_pointer[-2]; if (sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type)) { - REPLACE_OP(_NOP, 0, 0); + REPLACE_OP(inst, _NOP, 0, 0); } sym_set_type(left, &PyLong_Type); sym_set_type(right, &PyLong_Type); @@ -222,7 +222,7 @@ left = stack_pointer[-2]; if (sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type)) { - REPLACE_OP(_NOP, 0 ,0); + REPLACE_OP(inst, _NOP, 0 ,0); } sym_set_type(left, &PyFloat_Type); sym_set_type(right, &PyFloat_Type); From fcd31aff78d14fec70d150893416ef86aed77050 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 13 Feb 2024 19:06:51 +0800 Subject: [PATCH 46/52] rename inst -> this_instr --- Python/optimizer_analysis.c | 10 +++---- .../tier2_redundancy_eliminator_bytecodes.c | 10 +++---- Python/tier2_redundancy_eliminator_cases.c.h | 28 +++++++++---------- .../tier2_abstract_generator.py | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 0f55e19f629524..c87679dc1ed2e6 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -608,12 +608,12 @@ uop_redundancy_eliminator( goto error; } - for (_PyUOpInstruction *inst = trace; - inst < trace + trace_len && !op_is_end(inst->opcode); - inst++) { + for (_PyUOpInstruction *this_instr = trace; + this_instr < trace + trace_len && !op_is_end(this_instr->opcode); + this_instr++) { - int oparg = inst->oparg; - uint32_t opcode = inst->opcode; + int oparg = this_instr->oparg; + uint32_t opcode = this_instr->opcode; _Py_UOpsSymType **stack_pointer = ctx->frame->stack_pointer; diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index 5d9e8f12ef8140..a1a4067693172c 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -23,7 +23,7 @@ dummy_func(void) { _Py_UOpsSymType *bottom; _Py_UOpsAbstractFrame *frame; _Py_UOpsAbstractInterpContext *ctx; - _PyUOpInstruction *inst; + _PyUOpInstruction *this_instr; _PyBloomFilter *dependencies; int modified; @@ -64,7 +64,7 @@ dummy_func(void) { op(_GUARD_BOTH_INT, (left, right -- left, right)) { if (sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type)) { - REPLACE_OP(inst, _NOP, 0, 0); + REPLACE_OP(this_instr, _NOP, 0, 0); } sym_set_type(left, &PyLong_Type); sym_set_type(right, &PyLong_Type); @@ -73,7 +73,7 @@ dummy_func(void) { op(_GUARD_BOTH_FLOAT, (left, right -- left, right)) { if (sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type)) { - REPLACE_OP(inst, _NOP, 0 ,0); + REPLACE_OP(this_instr, _NOP, 0 ,0); } sym_set_type(left, &PyFloat_Type); sym_set_type(right, &PyFloat_Type); @@ -188,8 +188,8 @@ dummy_func(void) { (void)callable; - assert((inst + 2)->opcode == _PUSH_FRAME); - PyFunctionObject *func = (PyFunctionObject *)(inst + 2)->operand; + assert((this_instr + 2)->opcode == _PUSH_FRAME); + PyFunctionObject *func = (PyFunctionObject *)(this_instr + 2)->operand; if (func == NULL) { goto error; } diff --git a/Python/tier2_redundancy_eliminator_cases.c.h b/Python/tier2_redundancy_eliminator_cases.c.h index 84295f64a70ff9..9b4d0b4a17e44d 100644 --- a/Python/tier2_redundancy_eliminator_cases.c.h +++ b/Python/tier2_redundancy_eliminator_cases.c.h @@ -172,7 +172,7 @@ left = stack_pointer[-2]; if (sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type)) { - REPLACE_OP(inst, _NOP, 0, 0); + REPLACE_OP(this_instr, _NOP, 0, 0); } sym_set_type(left, &PyLong_Type); sym_set_type(right, &PyLong_Type); @@ -222,7 +222,7 @@ left = stack_pointer[-2]; if (sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type)) { - REPLACE_OP(inst, _NOP, 0 ,0); + REPLACE_OP(this_instr, _NOP, 0 ,0); } sym_set_type(left, &PyFloat_Type); sym_set_type(right, &PyFloat_Type); @@ -789,7 +789,7 @@ _Py_UOpsSymType *attr; _Py_UOpsSymType *null = NULL; owner = stack_pointer[-1]; - uint16_t index = (uint16_t)inst->operand; + uint16_t index = (uint16_t)this_instr->operand; _LOAD_ATTR_NOT_NULL (void)index; (void)owner; @@ -808,7 +808,7 @@ _Py_UOpsSymType *attr; _Py_UOpsSymType *null = NULL; owner = stack_pointer[-1]; - uint16_t index = (uint16_t)inst->operand; + uint16_t index = (uint16_t)this_instr->operand; _LOAD_ATTR_NOT_NULL (void)index; (void)owner; @@ -827,7 +827,7 @@ _Py_UOpsSymType *attr; _Py_UOpsSymType *null = NULL; owner = stack_pointer[-1]; - uint16_t hint = (uint16_t)inst->operand; + uint16_t hint = (uint16_t)this_instr->operand; _LOAD_ATTR_NOT_NULL (void)hint; (void)owner; @@ -842,7 +842,7 @@ _Py_UOpsSymType *attr; _Py_UOpsSymType *null = NULL; owner = stack_pointer[-1]; - uint16_t index = (uint16_t)inst->operand; + uint16_t index = (uint16_t)this_instr->operand; _LOAD_ATTR_NOT_NULL (void)index; (void)owner; @@ -861,7 +861,7 @@ _Py_UOpsSymType *attr; _Py_UOpsSymType *null = NULL; owner = stack_pointer[-1]; - PyObject *descr = (PyObject *)inst->operand; + PyObject *descr = (PyObject *)this_instr->operand; _LOAD_ATTR_NOT_NULL (void)descr; (void)owner; @@ -1269,7 +1269,7 @@ _Py_UOpsSymType *callable; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - uint32_t func_version = (uint32_t)inst->operand; + uint32_t func_version = (uint32_t)this_instr->operand; sym_set_type(callable, &PyFunction_Type); (void)self_or_null; (void)func_version; @@ -1290,8 +1290,8 @@ callable = stack_pointer[-2 - oparg]; int argcount = oparg; (void)callable; - assert((inst + 2)->opcode == _PUSH_FRAME); - PyFunctionObject *func = (PyFunctionObject *)(inst + 2)->operand; + assert((this_instr + 2)->opcode == _PUSH_FRAME); + PyFunctionObject *func = (PyFunctionObject *)(this_instr + 2)->operand; if (func == NULL) { goto error; } @@ -1604,7 +1604,7 @@ case _LOAD_CONST_INLINE: { _Py_UOpsSymType *value; - PyObject *ptr = (PyObject *)inst->operand; + PyObject *ptr = (PyObject *)this_instr->operand; value = sym_new_const(ctx, ptr); if (value == NULL) { goto out_of_space; @@ -1616,7 +1616,7 @@ case _LOAD_CONST_INLINE_BORROW: { _Py_UOpsSymType *value; - PyObject *ptr = (PyObject *)inst->operand; + PyObject *ptr = (PyObject *)this_instr->operand; value = sym_new_const(ctx, ptr); if (value == NULL) { goto out_of_space; @@ -1629,7 +1629,7 @@ case _LOAD_CONST_INLINE_WITH_NULL: { _Py_UOpsSymType *value; _Py_UOpsSymType *null; - PyObject *ptr = (PyObject *)inst->operand; + PyObject *ptr = (PyObject *)this_instr->operand; value = sym_new_const(ctx, ptr); if (value == NULL) { goto out_of_space; @@ -1647,7 +1647,7 @@ case _LOAD_CONST_INLINE_BORROW_WITH_NULL: { _Py_UOpsSymType *value; _Py_UOpsSymType *null; - PyObject *ptr = (PyObject *)inst->operand; + PyObject *ptr = (PyObject *)this_instr->operand; value = sym_new_const(ctx, ptr); if (value == NULL) { goto out_of_space; diff --git a/Tools/cases_generator/tier2_abstract_generator.py b/Tools/cases_generator/tier2_abstract_generator.py index e371b4646180f8..cc29b1660d26ed 100644 --- a/Tools/cases_generator/tier2_abstract_generator.py +++ b/Tools/cases_generator/tier2_abstract_generator.py @@ -133,7 +133,7 @@ def write_uop( else: type = f"uint{cache.size*16}_t " cast = f"uint{cache.size*16}_t" - out.emit(f"{type}{cache.name} = ({cast})inst->operand;\n") + out.emit(f"{type}{cache.name} = ({cast})this_instr->operand;\n") if override: replacement_funcs = { "DECREF_INPUTS": decref_inputs, From 92b211c53efce0176be9bbd9d892b9414e0d1c25 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 13 Feb 2024 19:15:05 +0800 Subject: [PATCH 47/52] address review --- Python/optimizer_analysis.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index c87679dc1ed2e6..40b916d1d7d725 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -631,14 +631,14 @@ uop_redundancy_eliminator( DPRINTF(3, " stack_level %d\n", STACK_LEVEL()); ctx->frame->stack_pointer = stack_pointer; assert(STACK_LEVEL() >= 0); - continue; - - out_of_space: - DPRINTF(1, "Out of space in abstract interpreter\n"); } abstractcontext_fini(ctx); + return 0; +out_of_space: + DPRINTF(1, "Out of space in abstract interpreter\n"); + abstractcontext_fini(ctx); return 0; error: @@ -744,7 +744,10 @@ _Py_uop_analyze_and_optimize( OPT_STAT_INC(optimizer_attempts); int err = remove_globals(frame, buffer, buffer_size, dependencies); - if (err <= 0) { + if (err == 0) { + goto not_ready; + } + if (err < 0) { goto error; } @@ -757,17 +760,13 @@ _Py_uop_analyze_and_optimize( if (err < 0) { goto error; } - - - + remove_unneeded_uops(buffer, buffer_size); OPT_STAT_INC(optimizer_successes); return 1; +not_ready: + return 0; error: - - // The only valid error we can raise is MemoryError. - // Other times it's not really errors but things like not being able - // to fetch a function version because the function got deleted. - return PyErr_Occurred() ? -1 : 0; + return -1; } From 1bf6ef8ef3b5e66a58190e25960819ca5a7c4281 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 13 Feb 2024 19:17:06 +0800 Subject: [PATCH 48/52] remove whitespace --- Python/optimizer_analysis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 40b916d1d7d725..41e53fd0d93081 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -760,7 +760,7 @@ _Py_uop_analyze_and_optimize( if (err < 0) { goto error; } - + remove_unneeded_uops(buffer, buffer_size); OPT_STAT_INC(optimizer_successes); From ea3755f29f701a6663699b71c0b807ef0ca29468 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 13 Feb 2024 19:19:59 +0800 Subject: [PATCH 49/52] remove assert --- Python/tier2_redundancy_eliminator_bytecodes.c | 1 - Python/tier2_redundancy_eliminator_cases.c.h | 1 - 2 files changed, 2 deletions(-) diff --git a/Python/tier2_redundancy_eliminator_bytecodes.c b/Python/tier2_redundancy_eliminator_bytecodes.c index a1a4067693172c..3272b187f20d0e 100644 --- a/Python/tier2_redundancy_eliminator_bytecodes.c +++ b/Python/tier2_redundancy_eliminator_bytecodes.c @@ -188,7 +188,6 @@ dummy_func(void) { (void)callable; - assert((this_instr + 2)->opcode == _PUSH_FRAME); PyFunctionObject *func = (PyFunctionObject *)(this_instr + 2)->operand; if (func == NULL) { goto error; diff --git a/Python/tier2_redundancy_eliminator_cases.c.h b/Python/tier2_redundancy_eliminator_cases.c.h index 9b4d0b4a17e44d..77a7f5b2360c3b 100644 --- a/Python/tier2_redundancy_eliminator_cases.c.h +++ b/Python/tier2_redundancy_eliminator_cases.c.h @@ -1290,7 +1290,6 @@ callable = stack_pointer[-2 - oparg]; int argcount = oparg; (void)callable; - assert((this_instr + 2)->opcode == _PUSH_FRAME); PyFunctionObject *func = (PyFunctionObject *)(this_instr + 2)->operand; if (func == NULL) { goto error; From f09e3c363d3fe79196df0a7be0bbd93063f9a62a Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 13 Feb 2024 19:30:02 +0800 Subject: [PATCH 50/52] remove enabled --- Python/pylifecycle.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 66de4a352a534a..230018068d751c 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1252,7 +1252,6 @@ init_interp_main(PyThreadState *tstate) if (_Py_get_xoption(&config->xoptions, L"uops") != NULL) { enabled = 1; } - enabled = 1; if (enabled) { #else // Always enable tier two for JIT builds (ignoring the environment From 9670b23e965653b0d3a2390aadeb6d5c9a7ba611 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 13 Feb 2024 19:31:25 +0800 Subject: [PATCH 51/52] fix up error codes --- Python/optimizer_analysis.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 41e53fd0d93081..98e3c3b3600470 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -605,7 +605,7 @@ uop_redundancy_eliminator( ctx, co, curr_stacklen, trace_len) < 0) { - goto error; + goto out_of_space; } for (_PyUOpInstruction *this_instr = trace; @@ -644,7 +644,7 @@ uop_redundancy_eliminator( error: DPRINTF(1, "Encountered error in abstract interpreter\n"); abstractcontext_fini(ctx); - return -1; + return 0; } From 38420c3909b71f79daf997c6c31ed8d6078af6fa Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 13 Feb 2024 19:36:19 +0800 Subject: [PATCH 52/52] fix error code again --- Python/optimizer_analysis.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 98e3c3b3600470..e02ca4d6acf6c1 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -589,6 +589,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, } while (0); +/* 1 for success, 0 for not ready, cannot error at the moment. */ static int uop_redundancy_eliminator( PyCodeObject *co, @@ -634,7 +635,7 @@ uop_redundancy_eliminator( } abstractcontext_fini(ctx); - return 0; + return 1; out_of_space: DPRINTF(1, "Out of space in abstract interpreter\n"); @@ -757,9 +758,10 @@ _Py_uop_analyze_and_optimize( (PyCodeObject *)frame->f_executable, buffer, buffer_size, curr_stacklen); - if (err < 0) { - goto error; + if (err == 0) { + goto not_ready; } + assert(err == 1); remove_unneeded_uops(buffer, buffer_size);