https://github.com/python/cpython/commit/f0f7b978be84c432139da1b107825aa2dc536854
commit: f0f7b978be84c432139da1b107825aa2dc536854
branch: main
author: Mark Shannon <m...@hotpy.org>
committer: markshannon <m...@hotpy.org>
date: 2025-01-20T15:49:15Z
summary:

GH-128939: Refactor JIT optimize structs (GH-128940)

files:
M Include/internal/pycore_optimizer.h
M Lib/test/test_capi/test_opt.py
M Lib/test/test_generated_cases.py
M Modules/_testinternalcapi.c
M Python/optimizer_analysis.c
M Python/optimizer_bytecodes.c
M Python/optimizer_cases.c.h
M Python/optimizer_symbols.c
M Tools/cases_generator/optimizer_generator.py

diff --git a/Include/internal/pycore_optimizer.h 
b/Include/internal/pycore_optimizer.h
index a02b9ab4291bfc..03ce4d4491acd7 100644
--- a/Include/internal/pycore_optimizer.h
+++ b/Include/internal/pycore_optimizer.h
@@ -148,15 +148,6 @@ extern PyTypeObject _PyDefaultOptimizer_Type;
 extern PyTypeObject _PyUOpExecutor_Type;
 extern PyTypeObject _PyUOpOptimizer_Type;
 
-/* Symbols */
-/* See explanation in optimizer_symbols.c */
-
-struct _Py_UopsSymbol {
-    int flags;  // 0 bits: Top; 2 or more bits: Bottom
-    PyTypeObject *typ;  // Borrowed reference
-    PyObject *const_val;  // Owned reference (!)
-    unsigned int type_version; // currently stores type version
-};
 
 #define UOP_FORMAT_TARGET 0
 #define UOP_FORMAT_JUMP 1
@@ -193,16 +184,63 @@ static inline uint16_t uop_get_error_target(const 
_PyUOpInstruction *inst)
 // handle before rejoining the rest of the program.
 #define MAX_CHAIN_DEPTH 4
 
-typedef struct _Py_UopsSymbol _Py_UopsSymbol;
+/* Symbols */
+/* See explanation in optimizer_symbols.c */
+
+
+typedef enum _JitSymType {
+    JIT_SYM_UNKNOWN_TAG = 1,
+    JIT_SYM_NULL_TAG = 2,
+    JIT_SYM_NON_NULL_TAG = 3,
+    JIT_SYM_BOTTOM_TAG = 4,
+    JIT_SYM_TYPE_VERSION_TAG = 5,
+    JIT_SYM_KNOWN_CLASS_TAG = 6,
+    JIT_SYM_KNOWN_VALUE_TAG = 7,
+    JIT_SYM_TUPLE_TAG = 8,
+} JitSymType;
+
+typedef struct _jit_opt_known_class {
+    uint8_t tag;
+    uint32_t version;
+    PyTypeObject *type;
+} JitOptKnownClass;
+
+typedef struct _jit_opt_known_version {
+    uint8_t tag;
+    uint32_t version;
+} JitOptKnownVersion;
+
+typedef struct _jit_opt_known_value {
+    uint8_t tag;
+    PyObject *value;
+} JitOptKnownValue;
+
+#define MAX_SYMBOLIC_TUPLE_SIZE 7
+
+typedef struct _jit_opt_tuple {
+    uint8_t tag;
+    uint8_t length;
+    uint16_t items[MAX_SYMBOLIC_TUPLE_SIZE];
+} JitOptTuple;
+
+typedef union _jit_opt_symbol {
+    uint8_t tag;
+    JitOptKnownClass cls;
+    JitOptKnownValue value;
+    JitOptKnownVersion version;
+    JitOptTuple tuple;
+} JitOptSymbol;
+
+
 
 struct _Py_UOpsAbstractFrame {
     // Max stacklen
     int stack_len;
     int locals_len;
 
-    _Py_UopsSymbol **stack_pointer;
-    _Py_UopsSymbol **stack;
-    _Py_UopsSymbol **locals;
+    JitOptSymbol **stack_pointer;
+    JitOptSymbol **stack;
+    JitOptSymbol **locals;
 };
 
 typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame;
@@ -210,10 +248,10 @@ typedef struct _Py_UOpsAbstractFrame 
_Py_UOpsAbstractFrame;
 typedef struct ty_arena {
     int ty_curr_number;
     int ty_max_number;
-    _Py_UopsSymbol arena[TY_ARENA_SIZE];
+    JitOptSymbol arena[TY_ARENA_SIZE];
 } ty_arena;
 
-struct _Py_UOpsContext {
+typedef struct _JitOptContext {
     char done;
     char out_of_space;
     bool contradiction;
@@ -225,46 +263,47 @@ struct _Py_UOpsContext {
     // Arena for the symbolic types.
     ty_arena t_arena;
 
-    _Py_UopsSymbol **n_consumed;
-    _Py_UopsSymbol **limit;
-    _Py_UopsSymbol *locals_and_stack[MAX_ABSTRACT_INTERP_SIZE];
-};
-
-typedef struct _Py_UOpsContext _Py_UOpsContext;
-
-extern bool _Py_uop_sym_is_null(_Py_UopsSymbol *sym);
-extern bool _Py_uop_sym_is_not_null(_Py_UopsSymbol *sym);
-extern bool _Py_uop_sym_is_const(_Py_UopsSymbol *sym);
-extern PyObject *_Py_uop_sym_get_const(_Py_UopsSymbol *sym);
-extern _Py_UopsSymbol *_Py_uop_sym_new_unknown(_Py_UOpsContext *ctx);
-extern _Py_UopsSymbol *_Py_uop_sym_new_not_null(_Py_UOpsContext *ctx);
-extern _Py_UopsSymbol *_Py_uop_sym_new_type(
-    _Py_UOpsContext *ctx, PyTypeObject *typ);
-extern _Py_UopsSymbol *_Py_uop_sym_new_const(_Py_UOpsContext *ctx, PyObject 
*const_val);
-extern _Py_UopsSymbol *_Py_uop_sym_new_null(_Py_UOpsContext *ctx);
-extern bool _Py_uop_sym_has_type(_Py_UopsSymbol *sym);
-extern bool _Py_uop_sym_matches_type(_Py_UopsSymbol *sym, PyTypeObject *typ);
-extern bool _Py_uop_sym_matches_type_version(_Py_UopsSymbol *sym, unsigned int 
version);
-extern void _Py_uop_sym_set_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym);
-extern void _Py_uop_sym_set_non_null(_Py_UOpsContext *ctx, _Py_UopsSymbol 
*sym);
-extern void _Py_uop_sym_set_type(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, 
PyTypeObject *typ);
-extern bool _Py_uop_sym_set_type_version(_Py_UOpsContext *ctx, _Py_UopsSymbol 
*sym, unsigned int version);
-extern void _Py_uop_sym_set_const(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, 
PyObject *const_val);
-extern bool _Py_uop_sym_is_bottom(_Py_UopsSymbol *sym);
-extern int _Py_uop_sym_truthiness(_Py_UopsSymbol *sym);
-extern PyTypeObject *_Py_uop_sym_get_type(_Py_UopsSymbol *sym);
-
-
-extern void _Py_uop_abstractcontext_init(_Py_UOpsContext *ctx);
-extern void _Py_uop_abstractcontext_fini(_Py_UOpsContext *ctx);
+    JitOptSymbol **n_consumed;
+    JitOptSymbol **limit;
+    JitOptSymbol *locals_and_stack[MAX_ABSTRACT_INTERP_SIZE];
+} JitOptContext;
+
+extern bool _Py_uop_sym_is_null(JitOptSymbol *sym);
+extern bool _Py_uop_sym_is_not_null(JitOptSymbol *sym);
+extern bool _Py_uop_sym_is_const(JitOptSymbol *sym);
+extern PyObject *_Py_uop_sym_get_const(JitOptSymbol *sym);
+extern JitOptSymbol *_Py_uop_sym_new_unknown(JitOptContext *ctx);
+extern JitOptSymbol *_Py_uop_sym_new_not_null(JitOptContext *ctx);
+extern JitOptSymbol *_Py_uop_sym_new_type(
+    JitOptContext *ctx, PyTypeObject *typ);
+extern JitOptSymbol *_Py_uop_sym_new_const(JitOptContext *ctx, PyObject 
*const_val);
+extern JitOptSymbol *_Py_uop_sym_new_null(JitOptContext *ctx);
+extern bool _Py_uop_sym_has_type(JitOptSymbol *sym);
+extern bool _Py_uop_sym_matches_type(JitOptSymbol *sym, PyTypeObject *typ);
+extern bool _Py_uop_sym_matches_type_version(JitOptSymbol *sym, unsigned int 
version);
+extern void _Py_uop_sym_set_null(JitOptContext *ctx, JitOptSymbol *sym);
+extern void _Py_uop_sym_set_non_null(JitOptContext *ctx, JitOptSymbol *sym);
+extern void _Py_uop_sym_set_type(JitOptContext *ctx, JitOptSymbol *sym, 
PyTypeObject *typ);
+extern bool _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptSymbol 
*sym, unsigned int version);
+extern void _Py_uop_sym_set_const(JitOptContext *ctx, JitOptSymbol *sym, 
PyObject *const_val);
+extern bool _Py_uop_sym_is_bottom(JitOptSymbol *sym);
+extern int _Py_uop_sym_truthiness(JitOptSymbol *sym);
+extern PyTypeObject *_Py_uop_sym_get_type(JitOptSymbol *sym);
+extern bool _Py_uop_sym_is_immortal(JitOptSymbol *sym);
+extern JitOptSymbol *_Py_uop_sym_new_tuple(JitOptContext *ctx, int size, 
JitOptSymbol **args);
+extern JitOptSymbol *_Py_uop_sym_tuple_getitem(JitOptContext *ctx, 
JitOptSymbol *sym, int item);
+extern int _Py_uop_sym_tuple_length(JitOptSymbol *sym);
+
+extern void _Py_uop_abstractcontext_init(JitOptContext *ctx);
+extern void _Py_uop_abstractcontext_fini(JitOptContext *ctx);
 
 extern _Py_UOpsAbstractFrame *_Py_uop_frame_new(
-    _Py_UOpsContext *ctx,
+    JitOptContext *ctx,
     PyCodeObject *co,
     int curr_stackentries,
-    _Py_UopsSymbol **args,
+    JitOptSymbol **args,
     int arg_len);
-extern int _Py_uop_frame_pop(_Py_UOpsContext *ctx);
+extern int _Py_uop_frame_pop(JitOptContext *ctx);
 
 PyAPI_FUNC(PyObject *) _Py_uop_symbols_test(PyObject *self, PyObject *ignored);
 
diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py
index a74b8fdd3923b7..9cfc6c142da6cd 100644
--- a/Lib/test/test_capi/test_opt.py
+++ b/Lib/test/test_capi/test_opt.py
@@ -1465,6 +1465,25 @@ def f(l: complex, r: complex) -> None:
             with self.subTest(l=l, r=r, x=x, y=y):
                 script_helper.assert_python_ok("-c", s)
 
+    def test_symbols_flow_through_tuples(self):
+        def testfunc(n):
+            for _ in range(n):
+                a = 1
+                b = 2
+                t = a, b
+                x, y = t
+                r = x + y
+            return r
+
+        res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
+        self.assertEqual(res, 3)
+        self.assertIsNotNone(ex)
+        uops = get_opnames(ex)
+        self.assertIn("_BINARY_OP_ADD_INT", uops)
+        self.assertNotIn("_GUARD_BOTH_INT", uops)
+        self.assertNotIn("_GUARD_NOS_INT", uops)
+        self.assertNotIn("_GUARD_TOS_INT", uops)
+
     def test_decref_escapes(self):
         class Convert9999ToNone:
             def __del__(self):
diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py
index 7a50a29bb0126c..aa92145266961a 100644
--- a/Lib/test/test_generated_cases.py
+++ b/Lib/test/test_generated_cases.py
@@ -1842,8 +1842,8 @@ def test_overridden_abstract_args(self):
         """
         output = """
         case OP: {
-            _Py_UopsSymbol *arg1;
-            _Py_UopsSymbol *out;
+            JitOptSymbol *arg1;
+            JitOptSymbol *out;
             arg1 = stack_pointer[-1];
             out = EGGS(arg1);
             stack_pointer[-1] = out;
@@ -1851,7 +1851,7 @@ def test_overridden_abstract_args(self):
         }
 
         case OP2: {
-            _Py_UopsSymbol *out;
+            JitOptSymbol *out;
             out = sym_new_not_null(ctx);
             stack_pointer[-1] = out;
             break;
@@ -1876,14 +1876,14 @@ def test_no_overridden_case(self):
         """
         output = """
         case OP: {
-            _Py_UopsSymbol *out;
+            JitOptSymbol *out;
             out = sym_new_not_null(ctx);
             stack_pointer[-1] = out;
             break;
         }
 
         case OP2: {
-            _Py_UopsSymbol *out;
+            JitOptSymbol *out;
             out = NULL;
             stack_pointer[-1] = out;
             break;
diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c
index aae09f620b8898..e77df5b57b0504 100644
--- a/Modules/_testinternalcapi.c
+++ b/Modules/_testinternalcapi.c
@@ -27,7 +27,7 @@
 #include "pycore_instruction_sequence.h"  // _PyInstructionSequence_New()
 #include "pycore_long.h"          // _PyLong_Sign()
 #include "pycore_object.h"        // _PyObject_IsFreed()
-#include "pycore_optimizer.h"     // _Py_UopsSymbol, etc.
+#include "pycore_optimizer.h"     // JitOptSymbol, etc.
 #include "pycore_pathconfig.h"    // _PyPathConfig_ClearGlobal()
 #include "pycore_pyerrors.h"      // _PyErr_ChainExceptions1()
 #include "pycore_pylifecycle.h"   // _PyInterpreterConfig_AsDict()
diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c
index 0ef15c630e91db..b9ac30ea04e4e8 100644
--- a/Python/optimizer_analysis.c
+++ b/Python/optimizer_analysis.c
@@ -368,13 +368,17 @@ remove_globals(_PyInterpreterFrame *frame, 
_PyUOpInstruction *buffer,
 #define sym_truthiness _Py_uop_sym_truthiness
 #define frame_new _Py_uop_frame_new
 #define frame_pop _Py_uop_frame_pop
+#define sym_new_tuple _Py_uop_sym_new_tuple
+#define sym_tuple_getitem _Py_uop_sym_tuple_getitem
+#define sym_tuple_length _Py_uop_sym_tuple_length
+#define sym_is_immortal _Py_uop_sym_is_immortal
 
 static int
 optimize_to_bool(
     _PyUOpInstruction *this_instr,
-    _Py_UOpsContext *ctx,
-    _Py_UopsSymbol *value,
-    _Py_UopsSymbol **result_ptr)
+    JitOptContext *ctx,
+    JitOptSymbol *value,
+    JitOptSymbol **result_ptr)
 {
     if (sym_matches_type(value, &PyBool_Type)) {
         REPLACE_OP(this_instr, _NOP, 0, 0);
@@ -460,8 +464,8 @@ optimize_uops(
 )
 {
 
-    _Py_UOpsContext context;
-    _Py_UOpsContext *ctx = &context;
+    JitOptContext context;
+    JitOptContext *ctx = &context;
     uint32_t opcode = UINT16_MAX;
     int curr_space = 0;
     int max_space = 0;
@@ -486,7 +490,7 @@ optimize_uops(
 
         int oparg = this_instr->oparg;
         opcode = this_instr->opcode;
-        _Py_UopsSymbol **stack_pointer = ctx->frame->stack_pointer;
+        JitOptSymbol **stack_pointer = ctx->frame->stack_pointer;
 
 #ifdef Py_DEBUG
         if (get_lltrace() >= 3) {
diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c
index 4d96ada5acf00f..881a607ca2aa29 100644
--- a/Python/optimizer_bytecodes.c
+++ b/Python/optimizer_bytecodes.c
@@ -6,8 +6,6 @@
 
 #define op(name, ...) /* NAME is ignored */
 
-typedef struct _Py_UopsSymbol _Py_UopsSymbol;
-typedef struct _Py_UOpsContext _Py_UOpsContext;
 typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame;
 
 /* Shortened forms for convenience */
@@ -32,13 +30,17 @@ typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame;
 #define sym_is_bottom _Py_uop_sym_is_bottom
 #define frame_new _Py_uop_frame_new
 #define frame_pop _Py_uop_frame_pop
+#define sym_new_tuple _Py_uop_sym_new_tuple
+#define sym_tuple_getitem _Py_uop_sym_tuple_getitem
+#define sym_tuple_length _Py_uop_sym_tuple_length
+#define sym_is_immortal _Py_uop_sym_is_immortal
 
 extern int
 optimize_to_bool(
     _PyUOpInstruction *this_instr,
-    _Py_UOpsContext *ctx,
-    _Py_UopsSymbol *value,
-    _Py_UopsSymbol **result_ptr);
+    JitOptContext *ctx,
+    JitOptSymbol *value,
+    JitOptSymbol **result_ptr);
 
 extern void
 eliminate_pop_guard(_PyUOpInstruction *this_instr, bool exit);
@@ -50,17 +52,17 @@ dummy_func(void) {
 
     PyCodeObject *co;
     int oparg;
-    _Py_UopsSymbol *flag;
-    _Py_UopsSymbol *left;
-    _Py_UopsSymbol *right;
-    _Py_UopsSymbol *value;
-    _Py_UopsSymbol *res;
-    _Py_UopsSymbol *iter;
-    _Py_UopsSymbol *top;
-    _Py_UopsSymbol *bottom;
+    JitOptSymbol *flag;
+    JitOptSymbol *left;
+    JitOptSymbol *right;
+    JitOptSymbol *value;
+    JitOptSymbol *res;
+    JitOptSymbol *iter;
+    JitOptSymbol *top;
+    JitOptSymbol *bottom;
     _Py_UOpsAbstractFrame *frame;
     _Py_UOpsAbstractFrame *new_frame;
-    _Py_UOpsContext *ctx;
+    JitOptContext *ctx;
     _PyUOpInstruction *this_instr;
     _PyBloomFilter *dependencies;
     int modified;
@@ -85,7 +87,7 @@ dummy_func(void) {
 
     op(_LOAD_FAST_AND_CLEAR, (-- value)) {
         value = GETLOCAL(oparg);
-        _Py_UopsSymbol *temp = sym_new_null(ctx);
+        JitOptSymbol *temp = sym_new_null(ctx);
         GETLOCAL(oparg) = temp;
     }
 
@@ -365,7 +367,7 @@ dummy_func(void) {
     }
 
     op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right -- )) {
-        _Py_UopsSymbol *res;
+        JitOptSymbol *res;
         if (sym_is_const(left) && sym_is_const(right) &&
             sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, 
&PyUnicode_Type)) {
             PyObject *temp = PyUnicode_Concat(sym_get_const(left), 
sym_get_const(right));
@@ -949,6 +951,22 @@ dummy_func(void) {
         res = sym_new_const(ctx, Py_True);
     }
 
+    op(_BUILD_TUPLE, (values[oparg] -- tup)) {
+        tup = sym_new_tuple(ctx, oparg, values);
+    }
+
+    op(_UNPACK_SEQUENCE_TWO_TUPLE, (seq -- val1, val0)) {
+        val0 = sym_tuple_getitem(ctx, seq, 0);
+        val1 = sym_tuple_getitem(ctx, seq, 1);
+    }
+
+    op(_UNPACK_SEQUENCE_TUPLE, (seq -- values[oparg])) {
+        for (int i = 0; i < oparg; i++) {
+            values[i] = sym_tuple_getitem(ctx, seq, i);
+        }
+    }
+
+
 // END BYTECODES //
 
 }
diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h
index 1f2b29c947434f..fa0b4ed4345320 100644
--- a/Python/optimizer_cases.c.h
+++ b/Python/optimizer_cases.c.h
@@ -26,7 +26,7 @@
         /* _MONITOR_RESUME is not a viable micro-op for tier 2 */
 
         case _LOAD_FAST_CHECK: {
-            _Py_UopsSymbol *value;
+            JitOptSymbol *value;
             value = GETLOCAL(oparg);
             // We guarantee this will error - just bail and don't optimize it.
             if (sym_is_null(value)) {
@@ -39,7 +39,7 @@
         }
 
         case _LOAD_FAST: {
-            _Py_UopsSymbol *value;
+            JitOptSymbol *value;
             value = GETLOCAL(oparg);
             stack_pointer[0] = value;
             stack_pointer += 1;
@@ -48,9 +48,9 @@
         }
 
         case _LOAD_FAST_AND_CLEAR: {
-            _Py_UopsSymbol *value;
+            JitOptSymbol *value;
             value = GETLOCAL(oparg);
-            _Py_UopsSymbol *temp = sym_new_null(ctx);
+            JitOptSymbol *temp = sym_new_null(ctx);
             GETLOCAL(oparg) = temp;
             stack_pointer[0] = value;
             stack_pointer += 1;
@@ -61,7 +61,7 @@
         /* _LOAD_CONST is not a viable micro-op for tier 2 */
 
         case _LOAD_CONST_MORTAL: {
-            _Py_UopsSymbol *value;
+            JitOptSymbol *value;
             PyObject *val = PyTuple_GET_ITEM(co->co_consts, this_instr->oparg);
             int opcode = _Py_IsImmortal(val) ? _LOAD_CONST_INLINE_BORROW : 
_LOAD_CONST_INLINE;
             REPLACE_OP(this_instr, opcode, 0, (uintptr_t)val);
@@ -73,7 +73,7 @@
         }
 
         case _LOAD_CONST_IMMORTAL: {
-            _Py_UopsSymbol *value;
+            JitOptSymbol *value;
             PyObject *val = PyTuple_GET_ITEM(co->co_consts, this_instr->oparg);
             REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, 
(uintptr_t)val);
             value = sym_new_const(ctx, val);
@@ -84,7 +84,7 @@
         }
 
         case _LOAD_SMALL_INT: {
-            _Py_UopsSymbol *value;
+            JitOptSymbol *value;
             PyObject *val = PyLong_FromLong(this_instr->oparg);
             value = sym_new_const(ctx, val);
             stack_pointer[0] = value;
@@ -94,7 +94,7 @@
         }
 
         case _STORE_FAST: {
-            _Py_UopsSymbol *value;
+            JitOptSymbol *value;
             value = stack_pointer[-1];
             GETLOCAL(oparg) = value;
             stack_pointer += -1;
@@ -109,7 +109,7 @@
         }
 
         case _PUSH_NULL: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_null(ctx);
             stack_pointer[0] = res;
             stack_pointer += 1;
@@ -124,7 +124,7 @@
         }
 
         case _END_SEND: {
-            _Py_UopsSymbol *val;
+            JitOptSymbol *val;
             val = sym_new_not_null(ctx);
             stack_pointer[-2] = val;
             stack_pointer += -1;
@@ -133,22 +133,22 @@
         }
 
         case _UNARY_NEGATIVE: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-1] = res;
             break;
         }
 
         case _UNARY_NOT: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-1] = res;
             break;
         }
 
         case _TO_BOOL: {
-            _Py_UopsSymbol *value;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *value;
+            JitOptSymbol *res;
             value = stack_pointer[-1];
             if (!optimize_to_bool(this_instr, ctx, value, &res)) {
                 res = sym_new_type(ctx, &PyBool_Type);
@@ -158,8 +158,8 @@
         }
 
         case _TO_BOOL_BOOL: {
-            _Py_UopsSymbol *value;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *value;
+            JitOptSymbol *res;
             value = stack_pointer[-1];
             if (!optimize_to_bool(this_instr, ctx, value, &res)) {
                 sym_set_type(value, &PyBool_Type);
@@ -170,8 +170,8 @@
         }
 
         case _TO_BOOL_INT: {
-            _Py_UopsSymbol *value;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *value;
+            JitOptSymbol *res;
             value = stack_pointer[-1];
             if (!optimize_to_bool(this_instr, ctx, value, &res)) {
                 sym_set_type(value, &PyLong_Type);
@@ -182,8 +182,8 @@
         }
 
         case _TO_BOOL_LIST: {
-            _Py_UopsSymbol *value;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *value;
+            JitOptSymbol *res;
             value = stack_pointer[-1];
             if (!optimize_to_bool(this_instr, ctx, value, &res)) {
                 sym_set_type(value, &PyList_Type);
@@ -194,8 +194,8 @@
         }
 
         case _TO_BOOL_NONE: {
-            _Py_UopsSymbol *value;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *value;
+            JitOptSymbol *res;
             value = stack_pointer[-1];
             if (!optimize_to_bool(this_instr, ctx, value, &res)) {
                 sym_set_const(value, Py_None);
@@ -206,8 +206,8 @@
         }
 
         case _TO_BOOL_STR: {
-            _Py_UopsSymbol *value;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *value;
+            JitOptSymbol *res;
             value = stack_pointer[-1];
             if (!optimize_to_bool(this_instr, ctx, value, &res)) {
                 res = sym_new_type(ctx, &PyBool_Type);
@@ -218,22 +218,22 @@
         }
 
         case _REPLACE_WITH_TRUE: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_const(ctx, Py_True);
             stack_pointer[-1] = res;
             break;
         }
 
         case _UNARY_INVERT: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-1] = res;
             break;
         }
 
         case _GUARD_BOTH_INT: {
-            _Py_UopsSymbol *right;
-            _Py_UopsSymbol *left;
+            JitOptSymbol *right;
+            JitOptSymbol *left;
             right = stack_pointer[-1];
             left = stack_pointer[-2];
             if (sym_matches_type(left, &PyLong_Type)) {
@@ -263,9 +263,9 @@
         }
 
         case _BINARY_OP_MULTIPLY_INT: {
-            _Py_UopsSymbol *right;
-            _Py_UopsSymbol *left;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *right;
+            JitOptSymbol *left;
+            JitOptSymbol *res;
             right = stack_pointer[-1];
             left = stack_pointer[-2];
             if (sym_is_const(left) && sym_is_const(right) &&
@@ -296,9 +296,9 @@
         }
 
         case _BINARY_OP_ADD_INT: {
-            _Py_UopsSymbol *right;
-            _Py_UopsSymbol *left;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *right;
+            JitOptSymbol *left;
+            JitOptSymbol *res;
             right = stack_pointer[-1];
             left = stack_pointer[-2];
             if (sym_is_const(left) && sym_is_const(right) &&
@@ -329,9 +329,9 @@
         }
 
         case _BINARY_OP_SUBTRACT_INT: {
-            _Py_UopsSymbol *right;
-            _Py_UopsSymbol *left;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *right;
+            JitOptSymbol *left;
+            JitOptSymbol *res;
             right = stack_pointer[-1];
             left = stack_pointer[-2];
             if (sym_is_const(left) && sym_is_const(right) &&
@@ -362,8 +362,8 @@
         }
 
         case _GUARD_BOTH_FLOAT: {
-            _Py_UopsSymbol *right;
-            _Py_UopsSymbol *left;
+            JitOptSymbol *right;
+            JitOptSymbol *left;
             right = stack_pointer[-1];
             left = stack_pointer[-2];
             if (sym_matches_type(left, &PyFloat_Type)) {
@@ -393,9 +393,9 @@
         }
 
         case _BINARY_OP_MULTIPLY_FLOAT: {
-            _Py_UopsSymbol *right;
-            _Py_UopsSymbol *left;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *right;
+            JitOptSymbol *left;
+            JitOptSymbol *res;
             right = stack_pointer[-1];
             left = stack_pointer[-2];
             if (sym_is_const(left) && sym_is_const(right) &&
@@ -427,9 +427,9 @@
         }
 
         case _BINARY_OP_ADD_FLOAT: {
-            _Py_UopsSymbol *right;
-            _Py_UopsSymbol *left;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *right;
+            JitOptSymbol *left;
+            JitOptSymbol *res;
             right = stack_pointer[-1];
             left = stack_pointer[-2];
             if (sym_is_const(left) && sym_is_const(right) &&
@@ -461,9 +461,9 @@
         }
 
         case _BINARY_OP_SUBTRACT_FLOAT: {
-            _Py_UopsSymbol *right;
-            _Py_UopsSymbol *left;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *right;
+            JitOptSymbol *left;
+            JitOptSymbol *res;
             right = stack_pointer[-1];
             left = stack_pointer[-2];
             if (sym_is_const(left) && sym_is_const(right) &&
@@ -495,8 +495,8 @@
         }
 
         case _GUARD_BOTH_UNICODE: {
-            _Py_UopsSymbol *right;
-            _Py_UopsSymbol *left;
+            JitOptSymbol *right;
+            JitOptSymbol *left;
             right = stack_pointer[-1];
             left = stack_pointer[-2];
             if (sym_matches_type(left, &PyUnicode_Type) &&
@@ -509,9 +509,9 @@
         }
 
         case _BINARY_OP_ADD_UNICODE: {
-            _Py_UopsSymbol *right;
-            _Py_UopsSymbol *left;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *right;
+            JitOptSymbol *left;
+            JitOptSymbol *res;
             right = stack_pointer[-1];
             left = stack_pointer[-2];
             if (sym_is_const(left) && sym_is_const(right) &&
@@ -536,11 +536,11 @@
         }
 
         case _BINARY_OP_INPLACE_ADD_UNICODE: {
-            _Py_UopsSymbol *right;
-            _Py_UopsSymbol *left;
+            JitOptSymbol *right;
+            JitOptSymbol *left;
             right = stack_pointer[-1];
             left = stack_pointer[-2];
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             if (sym_is_const(left) && sym_is_const(right) &&
                 sym_matches_type(left, &PyUnicode_Type) && 
sym_matches_type(right, &PyUnicode_Type)) {
                 PyObject *temp = PyUnicode_Concat(sym_get_const(left), 
sym_get_const(right));
@@ -567,7 +567,7 @@
         }
 
         case _BINARY_OP_EXTEND: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2] = res;
             stack_pointer += -1;
@@ -576,7 +576,7 @@
         }
 
         case _BINARY_SUBSCR: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2] = res;
             stack_pointer += -1;
@@ -585,7 +585,7 @@
         }
 
         case _BINARY_SLICE: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-3] = res;
             stack_pointer += -2;
@@ -600,7 +600,7 @@
         }
 
         case _BINARY_SUBSCR_LIST_INT: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2] = res;
             stack_pointer += -1;
@@ -609,7 +609,7 @@
         }
 
         case _BINARY_SUBSCR_STR_INT: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2] = res;
             stack_pointer += -1;
@@ -618,7 +618,7 @@
         }
 
         case _BINARY_SUBSCR_TUPLE_INT: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2] = res;
             stack_pointer += -1;
@@ -627,7 +627,7 @@
         }
 
         case _BINARY_SUBSCR_DICT: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2] = res;
             stack_pointer += -1;
@@ -636,7 +636,7 @@
         }
 
         case _BINARY_SUBSCR_CHECK_FUNC: {
-            _Py_UopsSymbol *getitem;
+            JitOptSymbol *getitem;
             getitem = sym_new_not_null(ctx);
             stack_pointer[0] = getitem;
             stack_pointer += 1;
@@ -645,9 +645,9 @@
         }
 
         case _BINARY_SUBSCR_INIT_CALL: {
-            _Py_UopsSymbol *getitem;
-            _Py_UopsSymbol *sub;
-            _Py_UopsSymbol *container;
+            JitOptSymbol *getitem;
+            JitOptSymbol *sub;
+            JitOptSymbol *container;
             _Py_UOpsAbstractFrame *new_frame;
             getitem = stack_pointer[-1];
             sub = stack_pointer[-2];
@@ -657,7 +657,7 @@
             (void)getitem;
             new_frame = NULL;
             ctx->done = true;
-            stack_pointer[-3] = (_Py_UopsSymbol *)new_frame;
+            stack_pointer[-3] = (JitOptSymbol *)new_frame;
             stack_pointer += -2;
             assert(WITHIN_STACK_BOUNDS());
             break;
@@ -700,14 +700,14 @@
         }
 
         case _CALL_INTRINSIC_1: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-1] = res;
             break;
         }
 
         case _CALL_INTRINSIC_2: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2] = res;
             stack_pointer += -1;
@@ -716,8 +716,8 @@
         }
 
         case _RETURN_VALUE: {
-            _Py_UopsSymbol *retval;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *retval;
+            JitOptSymbol *res;
             retval = stack_pointer[-1];
             stack_pointer += -1;
             assert(WITHIN_STACK_BOUNDS());
@@ -744,14 +744,14 @@
         }
 
         case _GET_AITER: {
-            _Py_UopsSymbol *iter;
+            JitOptSymbol *iter;
             iter = sym_new_not_null(ctx);
             stack_pointer[-1] = iter;
             break;
         }
 
         case _GET_ANEXT: {
-            _Py_UopsSymbol *awaitable;
+            JitOptSymbol *awaitable;
             awaitable = sym_new_not_null(ctx);
             stack_pointer[0] = awaitable;
             stack_pointer += 1;
@@ -760,7 +760,7 @@
         }
 
         case _GET_AWAITABLE: {
-            _Py_UopsSymbol *iter;
+            JitOptSymbol *iter;
             iter = sym_new_not_null(ctx);
             stack_pointer[-1] = iter;
             break;
@@ -775,7 +775,7 @@
         }
 
         case _YIELD_VALUE: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_unknown(ctx);
             stack_pointer[-1] = res;
             break;
@@ -788,7 +788,7 @@
         }
 
         case _LOAD_COMMON_CONSTANT: {
-            _Py_UopsSymbol *value;
+            JitOptSymbol *value;
             value = sym_new_not_null(ctx);
             stack_pointer[0] = value;
             stack_pointer += 1;
@@ -797,7 +797,7 @@
         }
 
         case _LOAD_BUILD_CLASS: {
-            _Py_UopsSymbol *bc;
+            JitOptSymbol *bc;
             bc = sym_new_not_null(ctx);
             stack_pointer[0] = bc;
             stack_pointer += 1;
@@ -816,8 +816,8 @@
         }
 
         case _UNPACK_SEQUENCE: {
-            _Py_UopsSymbol *seq;
-            _Py_UopsSymbol **values;
+            JitOptSymbol *seq;
+            JitOptSymbol **values;
             seq = stack_pointer[-1];
             values = &stack_pointer[-1];
             /* This has to be done manually */
@@ -831,10 +831,12 @@
         }
 
         case _UNPACK_SEQUENCE_TWO_TUPLE: {
-            _Py_UopsSymbol *val1;
-            _Py_UopsSymbol *val0;
-            val1 = sym_new_not_null(ctx);
-            val0 = sym_new_not_null(ctx);
+            JitOptSymbol *seq;
+            JitOptSymbol *val1;
+            JitOptSymbol *val0;
+            seq = stack_pointer[-1];
+            val0 = sym_tuple_getitem(ctx, seq, 0);
+            val1 = sym_tuple_getitem(ctx, seq, 1);
             stack_pointer[-1] = val1;
             stack_pointer[0] = val0;
             stack_pointer += 1;
@@ -843,10 +845,12 @@
         }
 
         case _UNPACK_SEQUENCE_TUPLE: {
-            _Py_UopsSymbol **values;
+            JitOptSymbol *seq;
+            JitOptSymbol **values;
+            seq = stack_pointer[-1];
             values = &stack_pointer[-1];
-            for (int _i = oparg; --_i >= 0;) {
-                values[_i] = sym_new_not_null(ctx);
+            for (int i = 0; i < oparg; i++) {
+                values[i] = sym_tuple_getitem(ctx, seq, i);
             }
             stack_pointer += -1 + oparg;
             assert(WITHIN_STACK_BOUNDS());
@@ -854,7 +858,7 @@
         }
 
         case _UNPACK_SEQUENCE_LIST: {
-            _Py_UopsSymbol **values;
+            JitOptSymbol **values;
             values = &stack_pointer[-1];
             for (int _i = oparg; --_i >= 0;) {
                 values[_i] = sym_new_not_null(ctx);
@@ -865,8 +869,8 @@
         }
 
         case _UNPACK_EX: {
-            _Py_UopsSymbol *seq;
-            _Py_UopsSymbol **values;
+            JitOptSymbol *seq;
+            JitOptSymbol **values;
             seq = stack_pointer[-1];
             values = &stack_pointer[-1];
             /* This has to be done manually */
@@ -903,7 +907,7 @@
         }
 
         case _LOAD_LOCALS: {
-            _Py_UopsSymbol *locals;
+            JitOptSymbol *locals;
             locals = sym_new_not_null(ctx);
             stack_pointer[0] = locals;
             stack_pointer += 1;
@@ -914,7 +918,7 @@
         /* _LOAD_FROM_DICT_OR_GLOBALS is not a viable micro-op for tier 2 */
 
         case _LOAD_NAME: {
-            _Py_UopsSymbol *v;
+            JitOptSymbol *v;
             v = sym_new_not_null(ctx);
             stack_pointer[0] = v;
             stack_pointer += 1;
@@ -923,8 +927,8 @@
         }
 
         case _LOAD_GLOBAL: {
-            _Py_UopsSymbol **res;
-            _Py_UopsSymbol *null = NULL;
+            JitOptSymbol **res;
+            JitOptSymbol *null = NULL;
             res = &stack_pointer[0];
             res[0] = sym_new_not_null(ctx);
             null = sym_new_null(ctx);
@@ -939,7 +943,7 @@
         }
 
         case _GUARD_GLOBALS_VERSION_PUSH_KEYS: {
-            _Py_UopsSymbol *globals_keys;
+            JitOptSymbol *globals_keys;
             uint16_t version = (uint16_t)this_instr->operand0;
             globals_keys = sym_new_unknown(ctx);
             (void)version;
@@ -950,7 +954,7 @@
         }
 
         case _GUARD_BUILTINS_VERSION_PUSH_KEYS: {
-            _Py_UopsSymbol *builtins_keys;
+            JitOptSymbol *builtins_keys;
             uint16_t version = (uint16_t)this_instr->operand0;
             builtins_keys = sym_new_unknown(ctx);
             (void)version;
@@ -961,8 +965,8 @@
         }
 
         case _LOAD_GLOBAL_MODULE_FROM_KEYS: {
-            _Py_UopsSymbol *res;
-            _Py_UopsSymbol *null = NULL;
+            JitOptSymbol *res;
+            JitOptSymbol *null = NULL;
             res = sym_new_not_null(ctx);
             null = sym_new_null(ctx);
             stack_pointer[-1] = res;
@@ -973,8 +977,8 @@
         }
 
         case _LOAD_GLOBAL_BUILTINS_FROM_KEYS: {
-            _Py_UopsSymbol *res;
-            _Py_UopsSymbol *null = NULL;
+            JitOptSymbol *res;
+            JitOptSymbol *null = NULL;
             res = sym_new_not_null(ctx);
             null = sym_new_null(ctx);
             stack_pointer[-1] = res;
@@ -997,14 +1001,14 @@
         }
 
         case _LOAD_FROM_DICT_OR_DEREF: {
-            _Py_UopsSymbol *value;
+            JitOptSymbol *value;
             value = sym_new_not_null(ctx);
             stack_pointer[-1] = value;
             break;
         }
 
         case _LOAD_DEREF: {
-            _Py_UopsSymbol *value;
+            JitOptSymbol *value;
             value = sym_new_not_null(ctx);
             stack_pointer[0] = value;
             stack_pointer += 1;
@@ -1023,7 +1027,7 @@
         }
 
         case _BUILD_STRING: {
-            _Py_UopsSymbol *str;
+            JitOptSymbol *str;
             str = sym_new_not_null(ctx);
             stack_pointer[-oparg] = str;
             stack_pointer += 1 - oparg;
@@ -1032,8 +1036,10 @@
         }
 
         case _BUILD_TUPLE: {
-            _Py_UopsSymbol *tup;
-            tup = sym_new_not_null(ctx);
+            JitOptSymbol **values;
+            JitOptSymbol *tup;
+            values = &stack_pointer[-oparg];
+            tup = sym_new_tuple(ctx, oparg, values);
             stack_pointer[-oparg] = tup;
             stack_pointer += 1 - oparg;
             assert(WITHIN_STACK_BOUNDS());
@@ -1041,7 +1047,7 @@
         }
 
         case _BUILD_LIST: {
-            _Py_UopsSymbol *list;
+            JitOptSymbol *list;
             list = sym_new_not_null(ctx);
             stack_pointer[-oparg] = list;
             stack_pointer += 1 - oparg;
@@ -1062,7 +1068,7 @@
         }
 
         case _BUILD_SET: {
-            _Py_UopsSymbol *set;
+            JitOptSymbol *set;
             set = sym_new_not_null(ctx);
             stack_pointer[-oparg] = set;
             stack_pointer += 1 - oparg;
@@ -1071,7 +1077,7 @@
         }
 
         case _BUILD_MAP: {
-            _Py_UopsSymbol *map;
+            JitOptSymbol *map;
             map = sym_new_not_null(ctx);
             stack_pointer[-oparg*2] = map;
             stack_pointer += 1 - oparg*2;
@@ -1104,7 +1110,7 @@
         /* _INSTRUMENTED_LOAD_SUPER_ATTR is not a viable micro-op for tier 2 */
 
         case _LOAD_SUPER_ATTR_ATTR: {
-            _Py_UopsSymbol *attr_st;
+            JitOptSymbol *attr_st;
             attr_st = sym_new_not_null(ctx);
             stack_pointer[-3] = attr_st;
             stack_pointer += -2;
@@ -1113,8 +1119,8 @@
         }
 
         case _LOAD_SUPER_ATTR_METHOD: {
-            _Py_UopsSymbol *attr;
-            _Py_UopsSymbol *self_or_null;
+            JitOptSymbol *attr;
+            JitOptSymbol *self_or_null;
             attr = sym_new_not_null(ctx);
             self_or_null = sym_new_not_null(ctx);
             stack_pointer[-3] = attr;
@@ -1125,9 +1131,9 @@
         }
 
         case _LOAD_ATTR: {
-            _Py_UopsSymbol *owner;
-            _Py_UopsSymbol *attr;
-            _Py_UopsSymbol *self_or_null = NULL;
+            JitOptSymbol *owner;
+            JitOptSymbol *attr;
+            JitOptSymbol *self_or_null = NULL;
             owner = stack_pointer[-1];
             (void)owner;
             attr = sym_new_not_null(ctx);
@@ -1140,7 +1146,7 @@
         }
 
         case _GUARD_TYPE_VERSION: {
-            _Py_UopsSymbol *owner;
+            JitOptSymbol *owner;
             owner = stack_pointer[-1];
             uint32_t type_version = (uint32_t)this_instr->operand0;
             assert(type_version);
@@ -1174,9 +1180,9 @@
         }
 
         case _LOAD_ATTR_INSTANCE_VALUE: {
-            _Py_UopsSymbol *owner;
-            _Py_UopsSymbol *attr;
-            _Py_UopsSymbol *null = NULL;
+            JitOptSymbol *owner;
+            JitOptSymbol *attr;
+            JitOptSymbol *null = NULL;
             owner = stack_pointer[-1];
             uint16_t offset = (uint16_t)this_instr->operand0;
             attr = sym_new_not_null(ctx);
@@ -1191,8 +1197,8 @@
         }
 
         case _CHECK_ATTR_MODULE_PUSH_KEYS: {
-            _Py_UopsSymbol *owner;
-            _Py_UopsSymbol *mod_keys;
+            JitOptSymbol *owner;
+            JitOptSymbol *mod_keys;
             owner = stack_pointer[-1];
             uint32_t dict_version = (uint32_t)this_instr->operand0;
             (void)dict_version;
@@ -1222,9 +1228,9 @@
         }
 
         case _LOAD_ATTR_MODULE_FROM_KEYS: {
-            _Py_UopsSymbol *owner;
-            _Py_UopsSymbol *attr;
-            _Py_UopsSymbol *null = NULL;
+            JitOptSymbol *owner;
+            JitOptSymbol *attr;
+            JitOptSymbol *null = NULL;
             owner = stack_pointer[-2];
             uint16_t index = (uint16_t)this_instr->operand0;
             (void)index;
@@ -1263,8 +1269,8 @@
         }
 
         case _CHECK_ATTR_WITH_HINT: {
-            _Py_UopsSymbol *owner;
-            _Py_UopsSymbol *dict;
+            JitOptSymbol *owner;
+            JitOptSymbol *dict;
             owner = stack_pointer[-1];
             dict = sym_new_not_null(ctx);
             (void)owner;
@@ -1275,10 +1281,10 @@
         }
 
         case _LOAD_ATTR_WITH_HINT: {
-            _Py_UopsSymbol *dict;
-            _Py_UopsSymbol *owner;
-            _Py_UopsSymbol *attr;
-            _Py_UopsSymbol *null = NULL;
+            JitOptSymbol *dict;
+            JitOptSymbol *owner;
+            JitOptSymbol *attr;
+            JitOptSymbol *null = NULL;
             dict = stack_pointer[-1];
             owner = stack_pointer[-2];
             uint16_t hint = (uint16_t)this_instr->operand0;
@@ -1295,9 +1301,9 @@
         }
 
         case _LOAD_ATTR_SLOT: {
-            _Py_UopsSymbol *owner;
-            _Py_UopsSymbol *attr;
-            _Py_UopsSymbol *null = NULL;
+            JitOptSymbol *owner;
+            JitOptSymbol *attr;
+            JitOptSymbol *null = NULL;
             owner = stack_pointer[-1];
             uint16_t index = (uint16_t)this_instr->operand0;
             attr = sym_new_not_null(ctx);
@@ -1316,9 +1322,9 @@
         }
 
         case _LOAD_ATTR_CLASS: {
-            _Py_UopsSymbol *owner;
-            _Py_UopsSymbol *attr;
-            _Py_UopsSymbol *null = NULL;
+            JitOptSymbol *owner;
+            JitOptSymbol *attr;
+            JitOptSymbol *null = NULL;
             owner = stack_pointer[-1];
             PyObject *descr = (PyObject *)this_instr->operand0;
             attr = sym_new_not_null(ctx);
@@ -1333,7 +1339,7 @@
         }
 
         case _LOAD_ATTR_PROPERTY_FRAME: {
-            _Py_UopsSymbol *owner;
+            JitOptSymbol *owner;
             _Py_UOpsAbstractFrame *new_frame;
             owner = stack_pointer[-1];
             PyObject *fget = (PyObject *)this_instr->operand0;
@@ -1341,7 +1347,7 @@
             (void)owner;
             new_frame = NULL;
             ctx->done = true;
-            stack_pointer[-1] = (_Py_UopsSymbol *)new_frame;
+            stack_pointer[-1] = (JitOptSymbol *)new_frame;
             break;
         }
 
@@ -1370,9 +1376,9 @@
         }
 
         case _COMPARE_OP: {
-            _Py_UopsSymbol *right;
-            _Py_UopsSymbol *left;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *right;
+            JitOptSymbol *left;
+            JitOptSymbol *res;
             right = stack_pointer[-1];
             left = stack_pointer[-2];
             (void)left;
@@ -1394,9 +1400,9 @@
         }
 
         case _COMPARE_OP_FLOAT: {
-            _Py_UopsSymbol *right;
-            _Py_UopsSymbol *left;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *right;
+            JitOptSymbol *left;
+            JitOptSymbol *res;
             right = stack_pointer[-1];
             left = stack_pointer[-2];
             (void)left;
@@ -1409,9 +1415,9 @@
         }
 
         case _COMPARE_OP_INT: {
-            _Py_UopsSymbol *right;
-            _Py_UopsSymbol *left;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *right;
+            JitOptSymbol *left;
+            JitOptSymbol *res;
             right = stack_pointer[-1];
             left = stack_pointer[-2];
             (void)left;
@@ -1424,9 +1430,9 @@
         }
 
         case _COMPARE_OP_STR: {
-            _Py_UopsSymbol *right;
-            _Py_UopsSymbol *left;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *right;
+            JitOptSymbol *left;
+            JitOptSymbol *res;
             right = stack_pointer[-1];
             left = stack_pointer[-2];
             (void)left;
@@ -1439,9 +1445,9 @@
         }
 
         case _IS_OP: {
-            _Py_UopsSymbol *right;
-            _Py_UopsSymbol *left;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *right;
+            JitOptSymbol *left;
+            JitOptSymbol *res;
             right = stack_pointer[-1];
             left = stack_pointer[-2];
             (void)left;
@@ -1454,9 +1460,9 @@
         }
 
         case _CONTAINS_OP: {
-            _Py_UopsSymbol *right;
-            _Py_UopsSymbol *left;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *right;
+            JitOptSymbol *left;
+            JitOptSymbol *res;
             right = stack_pointer[-1];
             left = stack_pointer[-2];
             (void)left;
@@ -1469,7 +1475,7 @@
         }
 
         case _CONTAINS_OP_SET: {
-            _Py_UopsSymbol *b;
+            JitOptSymbol *b;
             b = sym_new_not_null(ctx);
             stack_pointer[-2] = b;
             stack_pointer += -1;
@@ -1478,7 +1484,7 @@
         }
 
         case _CONTAINS_OP_DICT: {
-            _Py_UopsSymbol *b;
+            JitOptSymbol *b;
             b = sym_new_not_null(ctx);
             stack_pointer[-2] = b;
             stack_pointer += -1;
@@ -1487,8 +1493,8 @@
         }
 
         case _CHECK_EG_MATCH: {
-            _Py_UopsSymbol *rest;
-            _Py_UopsSymbol *match;
+            JitOptSymbol *rest;
+            JitOptSymbol *match;
             rest = sym_new_not_null(ctx);
             match = sym_new_not_null(ctx);
             stack_pointer[-2] = rest;
@@ -1497,14 +1503,14 @@
         }
 
         case _CHECK_EXC_MATCH: {
-            _Py_UopsSymbol *b;
+            JitOptSymbol *b;
             b = sym_new_not_null(ctx);
             stack_pointer[-1] = b;
             break;
         }
 
         case _IMPORT_NAME: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2] = res;
             stack_pointer += -1;
@@ -1513,7 +1519,7 @@
         }
 
         case _IMPORT_FROM: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[0] = res;
             stack_pointer += 1;
@@ -1526,14 +1532,14 @@
         /* _POP_JUMP_IF_TRUE is not a viable micro-op for tier 2 */
 
         case _IS_NONE: {
-            _Py_UopsSymbol *b;
+            JitOptSymbol *b;
             b = sym_new_not_null(ctx);
             stack_pointer[-1] = b;
             break;
         }
 
         case _GET_LEN: {
-            _Py_UopsSymbol *len;
+            JitOptSymbol *len;
             len = sym_new_not_null(ctx);
             stack_pointer[0] = len;
             stack_pointer += 1;
@@ -1542,7 +1548,7 @@
         }
 
         case _MATCH_CLASS: {
-            _Py_UopsSymbol *attrs;
+            JitOptSymbol *attrs;
             attrs = sym_new_not_null(ctx);
             stack_pointer[-3] = attrs;
             stack_pointer += -2;
@@ -1551,7 +1557,7 @@
         }
 
         case _MATCH_MAPPING: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[0] = res;
             stack_pointer += 1;
@@ -1560,7 +1566,7 @@
         }
 
         case _MATCH_SEQUENCE: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[0] = res;
             stack_pointer += 1;
@@ -1569,7 +1575,7 @@
         }
 
         case _MATCH_KEYS: {
-            _Py_UopsSymbol *values_or_none;
+            JitOptSymbol *values_or_none;
             values_or_none = sym_new_not_null(ctx);
             stack_pointer[0] = values_or_none;
             stack_pointer += 1;
@@ -1578,14 +1584,14 @@
         }
 
         case _GET_ITER: {
-            _Py_UopsSymbol *iter;
+            JitOptSymbol *iter;
             iter = sym_new_not_null(ctx);
             stack_pointer[-1] = iter;
             break;
         }
 
         case _GET_YIELD_FROM_ITER: {
-            _Py_UopsSymbol *iter;
+            JitOptSymbol *iter;
             iter = sym_new_not_null(ctx);
             stack_pointer[-1] = iter;
             break;
@@ -1594,7 +1600,7 @@
         /* _FOR_ITER is not a viable micro-op for tier 2 */
 
         case _FOR_ITER_TIER_TWO: {
-            _Py_UopsSymbol *next;
+            JitOptSymbol *next;
             next = sym_new_not_null(ctx);
             stack_pointer[0] = next;
             stack_pointer += 1;
@@ -1615,7 +1621,7 @@
         }
 
         case _ITER_NEXT_LIST: {
-            _Py_UopsSymbol *next;
+            JitOptSymbol *next;
             next = sym_new_not_null(ctx);
             stack_pointer[0] = next;
             stack_pointer += 1;
@@ -1634,7 +1640,7 @@
         }
 
         case _ITER_NEXT_TUPLE: {
-            _Py_UopsSymbol *next;
+            JitOptSymbol *next;
             next = sym_new_not_null(ctx);
             stack_pointer[0] = next;
             stack_pointer += 1;
@@ -1653,8 +1659,8 @@
         }
 
         case _ITER_NEXT_RANGE: {
-            _Py_UopsSymbol *iter;
-            _Py_UopsSymbol *next;
+            JitOptSymbol *iter;
+            JitOptSymbol *next;
             iter = stack_pointer[-1];
             next = sym_new_type(ctx, &PyLong_Type);
             (void)iter;
@@ -1671,9 +1677,9 @@
         }
 
         case _LOAD_SPECIAL: {
-            _Py_UopsSymbol *owner;
-            _Py_UopsSymbol *attr;
-            _Py_UopsSymbol *self_or_null;
+            JitOptSymbol *owner;
+            JitOptSymbol *attr;
+            JitOptSymbol *self_or_null;
             owner = stack_pointer[-1];
             (void)owner;
             attr = sym_new_not_null(ctx);
@@ -1686,7 +1692,7 @@
         }
 
         case _WITH_EXCEPT_START: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[0] = res;
             stack_pointer += 1;
@@ -1695,8 +1701,8 @@
         }
 
         case _PUSH_EXC_INFO: {
-            _Py_UopsSymbol *prev_exc;
-            _Py_UopsSymbol *new_exc;
+            JitOptSymbol *prev_exc;
+            JitOptSymbol *new_exc;
             prev_exc = sym_new_not_null(ctx);
             new_exc = sym_new_not_null(ctx);
             stack_pointer[-1] = prev_exc;
@@ -1715,9 +1721,9 @@
         }
 
         case _LOAD_ATTR_METHOD_WITH_VALUES: {
-            _Py_UopsSymbol *owner;
-            _Py_UopsSymbol *attr;
-            _Py_UopsSymbol *self = NULL;
+            JitOptSymbol *owner;
+            JitOptSymbol *attr;
+            JitOptSymbol *self = NULL;
             owner = stack_pointer[-1];
             PyObject *descr = (PyObject *)this_instr->operand0;
             (void)descr;
@@ -1731,9 +1737,9 @@
         }
 
         case _LOAD_ATTR_METHOD_NO_DICT: {
-            _Py_UopsSymbol *owner;
-            _Py_UopsSymbol *attr;
-            _Py_UopsSymbol *self = NULL;
+            JitOptSymbol *owner;
+            JitOptSymbol *attr;
+            JitOptSymbol *self = NULL;
             owner = stack_pointer[-1];
             PyObject *descr = (PyObject *)this_instr->operand0;
             (void)descr;
@@ -1747,14 +1753,14 @@
         }
 
         case _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: {
-            _Py_UopsSymbol *attr;
+            JitOptSymbol *attr;
             attr = sym_new_not_null(ctx);
             stack_pointer[-1] = attr;
             break;
         }
 
         case _LOAD_ATTR_NONDESCRIPTOR_NO_DICT: {
-            _Py_UopsSymbol *attr;
+            JitOptSymbol *attr;
             attr = sym_new_not_null(ctx);
             stack_pointer[-1] = attr;
             break;
@@ -1765,9 +1771,9 @@
         }
 
         case _LOAD_ATTR_METHOD_LAZY_DICT: {
-            _Py_UopsSymbol *owner;
-            _Py_UopsSymbol *attr;
-            _Py_UopsSymbol *self = NULL;
+            JitOptSymbol *owner;
+            JitOptSymbol *attr;
+            JitOptSymbol *self = NULL;
             owner = stack_pointer[-1];
             PyObject *descr = (PyObject *)this_instr->operand0;
             (void)descr;
@@ -1781,11 +1787,11 @@
         }
 
         case _MAYBE_EXPAND_METHOD: {
-            _Py_UopsSymbol **args;
-            _Py_UopsSymbol *self_or_null;
-            _Py_UopsSymbol *callable;
-            _Py_UopsSymbol *func;
-            _Py_UopsSymbol *maybe_self;
+            JitOptSymbol **args;
+            JitOptSymbol *self_or_null;
+            JitOptSymbol *callable;
+            JitOptSymbol *func;
+            JitOptSymbol *maybe_self;
             args = &stack_pointer[-oparg];
             self_or_null = stack_pointer[-1 - oparg];
             callable = stack_pointer[-2 - oparg];
@@ -1805,8 +1811,8 @@
         /* _MONITOR_CALL is not a viable micro-op for tier 2 */
 
         case _PY_FRAME_GENERAL: {
-            _Py_UopsSymbol *self_or_null;
-            _Py_UopsSymbol *callable;
+            JitOptSymbol *self_or_null;
+            JitOptSymbol *callable;
             _Py_UOpsAbstractFrame *new_frame;
             self_or_null = stack_pointer[-1 - oparg];
             callable = stack_pointer[-2 - oparg];
@@ -1822,15 +1828,15 @@
                 break;
             }
             new_frame = frame_new(ctx, co, 0, NULL, 0);
-            stack_pointer[0] = (_Py_UopsSymbol *)new_frame;
+            stack_pointer[0] = (JitOptSymbol *)new_frame;
             stack_pointer += 1;
             assert(WITHIN_STACK_BOUNDS());
             break;
         }
 
         case _CHECK_FUNCTION_VERSION: {
-            _Py_UopsSymbol *self_or_null;
-            _Py_UopsSymbol *callable;
+            JitOptSymbol *self_or_null;
+            JitOptSymbol *callable;
             self_or_null = stack_pointer[-1 - oparg];
             callable = stack_pointer[-2 - oparg];
             uint32_t func_version = (uint32_t)this_instr->operand0;
@@ -1853,8 +1859,8 @@
         }
 
         case _EXPAND_METHOD: {
-            _Py_UopsSymbol **method;
-            _Py_UopsSymbol **self;
+            JitOptSymbol **method;
+            JitOptSymbol **self;
             method = &stack_pointer[-2 - oparg];
             self = &stack_pointer[-1 - oparg];
             method[0] = sym_new_not_null(ctx);
@@ -1867,7 +1873,7 @@
         }
 
         case _CALL_NON_PY_GENERAL: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2 - oparg] = res;
             stack_pointer += -1 - oparg;
@@ -1876,8 +1882,8 @@
         }
 
         case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: {
-            _Py_UopsSymbol *null;
-            _Py_UopsSymbol *callable;
+            JitOptSymbol *null;
+            JitOptSymbol *callable;
             null = stack_pointer[-1 - oparg];
             callable = stack_pointer[-2 - oparg];
             sym_set_null(null);
@@ -1886,9 +1892,9 @@
         }
 
         case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: {
-            _Py_UopsSymbol *callable;
-            _Py_UopsSymbol *func;
-            _Py_UopsSymbol *self;
+            JitOptSymbol *callable;
+            JitOptSymbol *func;
+            JitOptSymbol *self;
             callable = stack_pointer[-2 - oparg];
             (void)callable;
             func = sym_new_not_null(ctx);
@@ -1908,8 +1914,8 @@
         }
 
         case _CHECK_FUNCTION_EXACT_ARGS: {
-            _Py_UopsSymbol *self_or_null;
-            _Py_UopsSymbol *callable;
+            JitOptSymbol *self_or_null;
+            JitOptSymbol *callable;
             self_or_null = stack_pointer[-1 - oparg];
             callable = stack_pointer[-2 - oparg];
             assert(sym_matches_type(callable, &PyFunction_Type));
@@ -1933,9 +1939,9 @@
         }
 
         case _INIT_CALL_PY_EXACT_ARGS: {
-            _Py_UopsSymbol **args;
-            _Py_UopsSymbol *self_or_null;
-            _Py_UopsSymbol *callable;
+            JitOptSymbol **args;
+            JitOptSymbol *self_or_null;
+            JitOptSymbol *callable;
             _Py_UOpsAbstractFrame *new_frame;
             args = &stack_pointer[-oparg];
             self_or_null = stack_pointer[-1 - oparg];
@@ -1963,7 +1969,7 @@
             } else {
                 new_frame = frame_new(ctx, co, 0, NULL, 0);
             }
-            stack_pointer[0] = (_Py_UopsSymbol *)new_frame;
+            stack_pointer[0] = (JitOptSymbol *)new_frame;
             stack_pointer += 1;
             assert(WITHIN_STACK_BOUNDS());
             break;
@@ -2008,7 +2014,7 @@
         }
 
         case _CALL_TYPE_1: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-3] = res;
             stack_pointer += -2;
@@ -2017,7 +2023,7 @@
         }
 
         case _CALL_STR_1: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-3] = res;
             stack_pointer += -2;
@@ -2026,7 +2032,7 @@
         }
 
         case _CALL_TUPLE_1: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-3] = res;
             stack_pointer += -2;
@@ -2035,11 +2041,11 @@
         }
 
         case _CHECK_AND_ALLOCATE_OBJECT: {
-            _Py_UopsSymbol **args;
-            _Py_UopsSymbol *null;
-            _Py_UopsSymbol *callable;
-            _Py_UopsSymbol *self;
-            _Py_UopsSymbol *init;
+            JitOptSymbol **args;
+            JitOptSymbol *null;
+            JitOptSymbol *callable;
+            JitOptSymbol *self;
+            JitOptSymbol *init;
             args = &stack_pointer[-oparg];
             null = stack_pointer[-1 - oparg];
             callable = stack_pointer[-2 - oparg];
@@ -2057,9 +2063,9 @@
         }
 
         case _CREATE_INIT_FRAME: {
-            _Py_UopsSymbol **args;
-            _Py_UopsSymbol *init;
-            _Py_UopsSymbol *self;
+            JitOptSymbol **args;
+            JitOptSymbol *init;
+            JitOptSymbol *self;
             _Py_UOpsAbstractFrame *init_frame;
             args = &stack_pointer[-oparg];
             init = stack_pointer[-1 - oparg];
@@ -2069,7 +2075,7 @@
             (void)args;
             init_frame = NULL;
             ctx->done = true;
-            stack_pointer[-2 - oparg] = (_Py_UopsSymbol *)init_frame;
+            stack_pointer[-2 - oparg] = (JitOptSymbol *)init_frame;
             stack_pointer += -1 - oparg;
             assert(WITHIN_STACK_BOUNDS());
             break;
@@ -2082,7 +2088,7 @@
         }
 
         case _CALL_BUILTIN_CLASS: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2 - oparg] = res;
             stack_pointer += -1 - oparg;
@@ -2091,7 +2097,7 @@
         }
 
         case _CALL_BUILTIN_O: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2 - oparg] = res;
             stack_pointer += -1 - oparg;
@@ -2100,7 +2106,7 @@
         }
 
         case _CALL_BUILTIN_FAST: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2 - oparg] = res;
             stack_pointer += -1 - oparg;
@@ -2109,7 +2115,7 @@
         }
 
         case _CALL_BUILTIN_FAST_WITH_KEYWORDS: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2 - oparg] = res;
             stack_pointer += -1 - oparg;
@@ -2118,7 +2124,7 @@
         }
 
         case _CALL_LEN: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2 - oparg] = res;
             stack_pointer += -1 - oparg;
@@ -2127,7 +2133,7 @@
         }
 
         case _CALL_ISINSTANCE: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2 - oparg] = res;
             stack_pointer += -1 - oparg;
@@ -2142,7 +2148,7 @@
         }
 
         case _CALL_METHOD_DESCRIPTOR_O: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2 - oparg] = res;
             stack_pointer += -1 - oparg;
@@ -2151,7 +2157,7 @@
         }
 
         case _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2 - oparg] = res;
             stack_pointer += -1 - oparg;
@@ -2160,7 +2166,7 @@
         }
 
         case _CALL_METHOD_DESCRIPTOR_NOARGS: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2 - oparg] = res;
             stack_pointer += -1 - oparg;
@@ -2169,7 +2175,7 @@
         }
 
         case _CALL_METHOD_DESCRIPTOR_FAST: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2 - oparg] = res;
             stack_pointer += -1 - oparg;
@@ -2180,10 +2186,10 @@
         /* _INSTRUMENTED_CALL_KW is not a viable micro-op for tier 2 */
 
         case _MAYBE_EXPAND_METHOD_KW: {
-            _Py_UopsSymbol **func;
-            _Py_UopsSymbol **maybe_self;
-            _Py_UopsSymbol **args;
-            _Py_UopsSymbol *kwnames_out;
+            JitOptSymbol **func;
+            JitOptSymbol **maybe_self;
+            JitOptSymbol **args;
+            JitOptSymbol *kwnames_out;
             func = &stack_pointer[-3 - oparg];
             maybe_self = &stack_pointer[-2 - oparg];
             args = &stack_pointer[-1 - oparg];
@@ -2200,10 +2206,10 @@
         /* _DO_CALL_KW is not a viable micro-op for tier 2 */
 
         case _PY_FRAME_KW: {
-            _Py_UopsSymbol *kwnames;
-            _Py_UopsSymbol **args;
-            _Py_UopsSymbol *self_or_null;
-            _Py_UopsSymbol *callable;
+            JitOptSymbol *kwnames;
+            JitOptSymbol **args;
+            JitOptSymbol *self_or_null;
+            JitOptSymbol *callable;
             _Py_UOpsAbstractFrame *new_frame;
             kwnames = stack_pointer[-1];
             args = &stack_pointer[-1 - oparg];
@@ -2215,7 +2221,7 @@
             (void)kwnames;
             new_frame = NULL;
             ctx->done = true;
-            stack_pointer[-3 - oparg] = (_Py_UopsSymbol *)new_frame;
+            stack_pointer[-3 - oparg] = (JitOptSymbol *)new_frame;
             stack_pointer += -2 - oparg;
             assert(WITHIN_STACK_BOUNDS());
             break;
@@ -2230,8 +2236,8 @@
         }
 
         case _EXPAND_METHOD_KW: {
-            _Py_UopsSymbol **method;
-            _Py_UopsSymbol **self;
+            JitOptSymbol **method;
+            JitOptSymbol **self;
             method = &stack_pointer[-3 - oparg];
             self = &stack_pointer[-2 - oparg];
             method[0] = sym_new_not_null(ctx);
@@ -2244,7 +2250,7 @@
         }
 
         case _CALL_KW_NON_PY: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-3 - oparg] = res;
             stack_pointer += -2 - oparg;
@@ -2255,8 +2261,8 @@
         /* _INSTRUMENTED_CALL_FUNCTION_EX is not a viable micro-op for tier 2 
*/
 
         case _MAKE_CALLARGS_A_TUPLE: {
-            _Py_UopsSymbol *tuple;
-            _Py_UopsSymbol *kwargs_out = NULL;
+            JitOptSymbol *tuple;
+            JitOptSymbol *kwargs_out = NULL;
             tuple = sym_new_not_null(ctx);
             kwargs_out = sym_new_not_null(ctx);
             stack_pointer[-1 - (oparg & 1)] = tuple;
@@ -2267,14 +2273,14 @@
         /* _DO_CALL_FUNCTION_EX is not a viable micro-op for tier 2 */
 
         case _MAKE_FUNCTION: {
-            _Py_UopsSymbol *func;
+            JitOptSymbol *func;
             func = sym_new_not_null(ctx);
             stack_pointer[-1] = func;
             break;
         }
 
         case _SET_FUNCTION_ATTRIBUTE: {
-            _Py_UopsSymbol *func_out;
+            JitOptSymbol *func_out;
             func_out = sym_new_not_null(ctx);
             stack_pointer[-2] = func_out;
             stack_pointer += -1;
@@ -2283,7 +2289,7 @@
         }
 
         case _RETURN_GENERATOR: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             ctx->frame->stack_pointer = stack_pointer;
             frame_pop(ctx);
             stack_pointer = ctx->frame->stack_pointer;
@@ -2307,7 +2313,7 @@
         }
 
         case _BUILD_SLICE: {
-            _Py_UopsSymbol *slice;
+            JitOptSymbol *slice;
             slice = sym_new_not_null(ctx);
             stack_pointer[-2 - ((oparg == 3) ? 1 : 0)] = slice;
             stack_pointer += -1 - ((oparg == 3) ? 1 : 0);
@@ -2316,21 +2322,21 @@
         }
 
         case _CONVERT_VALUE: {
-            _Py_UopsSymbol *result;
+            JitOptSymbol *result;
             result = sym_new_not_null(ctx);
             stack_pointer[-1] = result;
             break;
         }
 
         case _FORMAT_SIMPLE: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-1] = res;
             break;
         }
 
         case _FORMAT_WITH_SPEC: {
-            _Py_UopsSymbol *res;
+            JitOptSymbol *res;
             res = sym_new_not_null(ctx);
             stack_pointer[-2] = res;
             stack_pointer += -1;
@@ -2339,8 +2345,8 @@
         }
 
         case _COPY: {
-            _Py_UopsSymbol *bottom;
-            _Py_UopsSymbol *top;
+            JitOptSymbol *bottom;
+            JitOptSymbol *top;
             bottom = stack_pointer[-1 - (oparg-1)];
             assert(oparg > 0);
             top = bottom;
@@ -2351,9 +2357,9 @@
         }
 
         case _BINARY_OP: {
-            _Py_UopsSymbol *right;
-            _Py_UopsSymbol *left;
-            _Py_UopsSymbol *res;
+            JitOptSymbol *right;
+            JitOptSymbol *left;
+            JitOptSymbol *res;
             right = stack_pointer[-1];
             left = stack_pointer[-2];
             bool lhs_int = sym_matches_type(left, &PyLong_Type);
@@ -2426,10 +2432,10 @@
         }
 
         case _SWAP: {
-            _Py_UopsSymbol *top_in;
-            _Py_UopsSymbol *bottom_in;
-            _Py_UopsSymbol *top_out;
-            _Py_UopsSymbol *bottom_out;
+            JitOptSymbol *top_in;
+            JitOptSymbol *bottom_in;
+            JitOptSymbol *top_out;
+            JitOptSymbol *bottom_out;
             top_in = stack_pointer[-1];
             bottom_in = stack_pointer[-2 - (oparg-2)];
             bottom_out = bottom_in;
@@ -2458,7 +2464,7 @@
         /* _INSTRUMENTED_POP_JUMP_IF_NOT_NONE is not a viable micro-op for 
tier 2 */
 
         case _GUARD_IS_TRUE_POP: {
-            _Py_UopsSymbol *flag;
+            JitOptSymbol *flag;
             flag = stack_pointer[-1];
             if (sym_is_const(flag)) {
                 PyObject *value = sym_get_const(flag);
@@ -2475,7 +2481,7 @@
         }
 
         case _GUARD_IS_FALSE_POP: {
-            _Py_UopsSymbol *flag;
+            JitOptSymbol *flag;
             flag = stack_pointer[-1];
             if (sym_is_const(flag)) {
                 PyObject *value = sym_get_const(flag);
@@ -2492,7 +2498,7 @@
         }
 
         case _GUARD_IS_NONE_POP: {
-            _Py_UopsSymbol *flag;
+            JitOptSymbol *flag;
             flag = stack_pointer[-1];
             if (sym_is_const(flag)) {
                 PyObject *value = sym_get_const(flag);
@@ -2517,7 +2523,7 @@
         }
 
         case _GUARD_IS_NOT_NONE_POP: {
-            _Py_UopsSymbol *flag;
+            JitOptSymbol *flag;
             flag = stack_pointer[-1];
             if (sym_is_const(flag)) {
                 PyObject *value = sym_get_const(flag);
@@ -2575,7 +2581,7 @@
         }
 
         case _LOAD_CONST_INLINE: {
-            _Py_UopsSymbol *value;
+            JitOptSymbol *value;
             PyObject *ptr = (PyObject *)this_instr->operand0;
             value = sym_new_const(ctx, ptr);
             stack_pointer[0] = value;
@@ -2585,7 +2591,7 @@
         }
 
         case _LOAD_CONST_INLINE_BORROW: {
-            _Py_UopsSymbol *value;
+            JitOptSymbol *value;
             PyObject *ptr = (PyObject *)this_instr->operand0;
             value = sym_new_const(ctx, ptr);
             stack_pointer[0] = value;
@@ -2595,15 +2601,15 @@
         }
 
         case _POP_TOP_LOAD_CONST_INLINE_BORROW: {
-            _Py_UopsSymbol *value;
+            JitOptSymbol *value;
             value = sym_new_not_null(ctx);
             stack_pointer[-1] = value;
             break;
         }
 
         case _LOAD_CONST_INLINE_WITH_NULL: {
-            _Py_UopsSymbol *value;
-            _Py_UopsSymbol *null;
+            JitOptSymbol *value;
+            JitOptSymbol *null;
             PyObject *ptr = (PyObject *)this_instr->operand0;
             value = sym_new_const(ctx, ptr);
             null = sym_new_null(ctx);
@@ -2615,8 +2621,8 @@
         }
 
         case _LOAD_CONST_INLINE_BORROW_WITH_NULL: {
-            _Py_UopsSymbol *value;
-            _Py_UopsSymbol *null;
+            JitOptSymbol *value;
+            JitOptSymbol *null;
             PyObject *ptr = (PyObject *)this_instr->operand0;
             value = sym_new_const(ctx, ptr);
             null = sym_new_null(ctx);
@@ -2632,8 +2638,8 @@
         }
 
         case _LOAD_GLOBAL_MODULE: {
-            _Py_UopsSymbol *res;
-            _Py_UopsSymbol *null = NULL;
+            JitOptSymbol *res;
+            JitOptSymbol *null = NULL;
             res = sym_new_not_null(ctx);
             null = sym_new_null(ctx);
             stack_pointer[0] = res;
@@ -2644,8 +2650,8 @@
         }
 
         case _LOAD_GLOBAL_BUILTINS: {
-            _Py_UopsSymbol *res;
-            _Py_UopsSymbol *null = NULL;
+            JitOptSymbol *res;
+            JitOptSymbol *null = NULL;
             res = sym_new_not_null(ctx);
             null = sym_new_null(ctx);
             stack_pointer[0] = res;
@@ -2656,8 +2662,8 @@
         }
 
         case _LOAD_ATTR_MODULE: {
-            _Py_UopsSymbol *attr;
-            _Py_UopsSymbol *null = NULL;
+            JitOptSymbol *attr;
+            JitOptSymbol *null = NULL;
             attr = sym_new_not_null(ctx);
             null = sym_new_null(ctx);
             stack_pointer[-1] = attr;
diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c
index 40cbf95e3d6d39..dcde8e7ce81577 100644
--- a/Python/optimizer_symbols.c
+++ b/Python/optimizer_symbols.c
@@ -28,11 +28,6 @@
    - Bottom: IS_NULL and NOT_NULL flags set, type and const_val NULL.
  */
 
-// Flags for below.
-#define IS_NULL    1 << 0
-#define NOT_NULL   1 << 1
-#define NO_SPACE   1 << 2
-
 #ifdef Py_DEBUG
 static inline int get_lltrace(void) {
     char *uop_debug = Py_GETENV("PYTHON_OPT_DEBUG");
@@ -48,187 +43,254 @@ static inline int get_lltrace(void) {
 #define DPRINTF(level, ...)
 #endif
 
-static _Py_UopsSymbol NO_SPACE_SYMBOL = {
-    .flags = IS_NULL | NOT_NULL | NO_SPACE,
-    .typ = NULL,
-    .const_val = NULL,
-    .type_version = 0,
+
+static JitOptSymbol NO_SPACE_SYMBOL = {
+    .tag = JIT_SYM_BOTTOM_TAG
 };
 
-_Py_UopsSymbol *
-out_of_space(_Py_UOpsContext *ctx)
+JitOptSymbol *
+out_of_space(JitOptContext *ctx)
 {
     ctx->done = true;
     ctx->out_of_space = true;
     return &NO_SPACE_SYMBOL;
 }
 
-static _Py_UopsSymbol *
-sym_new(_Py_UOpsContext *ctx)
+static JitOptSymbol *
+sym_new(JitOptContext *ctx)
 {
-    _Py_UopsSymbol *self = &ctx->t_arena.arena[ctx->t_arena.ty_curr_number];
+    JitOptSymbol *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->flags = 0;
-    self->typ = NULL;
-    self->const_val = NULL;
-    self->type_version = 0;
-
+    self->tag = JIT_SYM_UNKNOWN_TAG;
     return self;
 }
 
 static inline void
-sym_set_flag(_Py_UopsSymbol *sym, int flag)
-{
-    sym->flags |= flag;
-}
-
-static inline void
-sym_set_bottom(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym)
+sym_set_bottom(JitOptContext *ctx, JitOptSymbol *sym)
 {
-    sym_set_flag(sym, IS_NULL | NOT_NULL);
-    sym->typ = NULL;
-    Py_CLEAR(sym->const_val);
+    sym->tag = JIT_SYM_BOTTOM_TAG;
     ctx->done = true;
     ctx->contradiction = true;
 }
 
 bool
-_Py_uop_sym_is_bottom(_Py_UopsSymbol *sym)
+_Py_uop_sym_is_bottom(JitOptSymbol *sym)
 {
-    if ((sym->flags & IS_NULL) && (sym->flags & NOT_NULL)) {
-        assert(sym->flags == (IS_NULL | NOT_NULL));
-        assert(sym->typ == NULL);
-        assert(sym->const_val == NULL);
-        return true;
-    }
-    return false;
+    return sym->tag == JIT_SYM_BOTTOM_TAG;
 }
 
 bool
-_Py_uop_sym_is_not_null(_Py_UopsSymbol *sym)
-{
-    return sym->flags == NOT_NULL;
+_Py_uop_sym_is_not_null(JitOptSymbol *sym) {
+    return sym->tag == JIT_SYM_NON_NULL_TAG || sym->tag > JIT_SYM_BOTTOM_TAG;
 }
 
 bool
-_Py_uop_sym_is_null(_Py_UopsSymbol *sym)
+_Py_uop_sym_is_const(JitOptSymbol *sym)
 {
-    return sym->flags == IS_NULL;
+    return sym->tag == JIT_SYM_KNOWN_VALUE_TAG;
 }
 
 bool
-_Py_uop_sym_is_const(_Py_UopsSymbol *sym)
+_Py_uop_sym_is_null(JitOptSymbol *sym)
 {
-    return sym->const_val != NULL;
+    return sym->tag == JIT_SYM_NULL_TAG;
 }
 
+
 PyObject *
-_Py_uop_sym_get_const(_Py_UopsSymbol *sym)
+_Py_uop_sym_get_const(JitOptSymbol *sym)
 {
-    return sym->const_val;
+    if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) {
+        return sym->value.value;
+    }
+    return NULL;
 }
 
 void
-_Py_uop_sym_set_type(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, PyTypeObject 
*typ)
+_Py_uop_sym_set_type(JitOptContext *ctx, JitOptSymbol *sym, PyTypeObject *typ)
 {
-    assert(typ != NULL && PyType_Check(typ));
-    if (sym->flags & IS_NULL) {
-        sym_set_bottom(ctx, sym);
-        return;
-    }
-    if (sym->typ != NULL) {
-        if (sym->typ != typ) {
+    JitSymType tag = sym->tag;
+    switch(tag) {
+        case JIT_SYM_NULL_TAG:
             sym_set_bottom(ctx, sym);
             return;
-        }
-    }
-    else {
-        sym_set_flag(sym, NOT_NULL);
-        sym->typ = typ;
+        case JIT_SYM_KNOWN_CLASS_TAG:
+            if (sym->cls.type != typ) {
+                sym_set_bottom(ctx, sym);
+            }
+            return;
+        case JIT_SYM_TYPE_VERSION_TAG:
+            if (sym->version.version == typ->tp_version_tag) {
+                sym->tag = JIT_SYM_KNOWN_CLASS_TAG;
+                sym->cls.type = typ;
+                sym->cls.version = typ->tp_version_tag;
+            }
+            else {
+                sym_set_bottom(ctx, sym);
+            }
+            return;
+        case JIT_SYM_KNOWN_VALUE_TAG:
+            if (Py_TYPE(sym->value.value) != typ) {
+                Py_CLEAR(sym->value.value);
+                sym_set_bottom(ctx, sym);
+            }
+            return;
+        case JIT_SYM_TUPLE_TAG:
+            if (typ != &PyTuple_Type) {
+                sym_set_bottom(ctx, sym);
+            }
+            return;
+        case JIT_SYM_BOTTOM_TAG:
+            return;
+        case JIT_SYM_NON_NULL_TAG:
+        case JIT_SYM_UNKNOWN_TAG:
+            sym->tag = JIT_SYM_KNOWN_CLASS_TAG;
+            sym->cls.version = 0;
+            sym->cls.type = typ;
+            return;
     }
 }
 
 bool
-_Py_uop_sym_set_type_version(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, 
unsigned int version)
+_Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptSymbol *sym, unsigned 
int version)
 {
-    // if the type version was already set, then it must be different and we 
should set it to bottom
-    if (sym->type_version) {
-        sym_set_bottom(ctx, sym);
-        return false;
+    JitSymType tag = sym->tag;
+    switch(tag) {
+        case JIT_SYM_NULL_TAG:
+            sym_set_bottom(ctx, sym);
+            return false;
+        case JIT_SYM_KNOWN_CLASS_TAG:
+            if (sym->cls.type->tp_version_tag != version) {
+                sym_set_bottom(ctx, sym);
+                return false;
+            }
+            else {
+                sym->cls.version = version;
+                return true;
+            }
+        case JIT_SYM_KNOWN_VALUE_TAG:
+            Py_CLEAR(sym->value.value);
+            sym_set_bottom(ctx, sym);
+            return false;
+        case JIT_SYM_TUPLE_TAG:
+            sym_set_bottom(ctx, sym);
+            return false;
+        case JIT_SYM_TYPE_VERSION_TAG:
+            if (sym->version.version == version) {
+                return true;
+            }
+            sym_set_bottom(ctx, sym);
+            return false;
+        case JIT_SYM_BOTTOM_TAG:
+            return false;
+        case JIT_SYM_NON_NULL_TAG:
+        case JIT_SYM_UNKNOWN_TAG:
+            sym->tag = JIT_SYM_TYPE_VERSION_TAG;
+            sym->version.version = version;
+            return true;
     }
-    sym->type_version = version;
-    return true;
+    Py_UNREACHABLE();
+}
+
+static void make_const(JitOptSymbol *sym, PyObject *val)
+{
+    sym->tag = JIT_SYM_KNOWN_VALUE_TAG;
+    sym->value.value = Py_NewRef(val);
 }
 
 void
-_Py_uop_sym_set_const(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym, PyObject 
*const_val)
+_Py_uop_sym_set_const(JitOptContext *ctx, JitOptSymbol *sym, PyObject 
*const_val)
 {
-    assert(const_val != NULL);
-    if (sym->flags & IS_NULL) {
-        sym_set_bottom(ctx, sym);
-    }
-    PyTypeObject *typ = Py_TYPE(const_val);
-    if (sym->typ != NULL && sym->typ != typ) {
-        sym_set_bottom(ctx, sym);
-    }
-    if (sym->const_val != NULL) {
-        if (sym->const_val != const_val) {
-            // TODO: What if they're equal?
+    JitSymType tag = sym->tag;
+    switch(tag) {
+        case JIT_SYM_NULL_TAG:
             sym_set_bottom(ctx, sym);
-        }
-    }
-    else {
-        sym_set_flag(sym, NOT_NULL);
-        sym->typ = typ;
-        sym->const_val = Py_NewRef(const_val);
+            return;
+        case JIT_SYM_KNOWN_CLASS_TAG:
+            if (sym->cls.type != Py_TYPE(const_val)) {
+                sym_set_bottom(ctx, sym);
+                return;
+            }
+            make_const(sym, const_val);
+            return;
+        case JIT_SYM_KNOWN_VALUE_TAG:
+            if (sym->value.value != const_val) {
+                Py_CLEAR(sym->value.value);
+                sym_set_bottom(ctx, sym);
+            }
+            return;
+        case JIT_SYM_TUPLE_TAG:
+            sym_set_bottom(ctx, sym);
+            return;
+        case JIT_SYM_TYPE_VERSION_TAG:
+            if (sym->version.version != Py_TYPE(const_val)->tp_version_tag) {
+                sym_set_bottom(ctx, sym);
+                return;
+            }
+            make_const(sym, const_val);
+            return;
+        case JIT_SYM_BOTTOM_TAG:
+            return;
+        case JIT_SYM_NON_NULL_TAG:
+        case JIT_SYM_UNKNOWN_TAG:
+            make_const(sym, const_val);
+            return;
     }
 }
 
 void
-_Py_uop_sym_set_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym)
+_Py_uop_sym_set_null(JitOptContext *ctx, JitOptSymbol *sym)
 {
-    if (_Py_uop_sym_is_not_null(sym)) {
+    if (sym->tag == JIT_SYM_UNKNOWN_TAG) {
+        sym->tag = JIT_SYM_NULL_TAG;
+    }
+    else if (sym->tag > JIT_SYM_NULL_TAG) {
         sym_set_bottom(ctx, sym);
     }
-    sym_set_flag(sym, IS_NULL);
 }
 
 void
-_Py_uop_sym_set_non_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym)
+_Py_uop_sym_set_non_null(JitOptContext *ctx, JitOptSymbol *sym)
 {
-    if (_Py_uop_sym_is_null(sym)) {
+    if (sym->tag == JIT_SYM_UNKNOWN_TAG) {
+        sym->tag = JIT_SYM_NON_NULL_TAG;
+    }
+    else if (sym->tag == JIT_SYM_NULL_TAG) {
         sym_set_bottom(ctx, sym);
     }
-    sym_set_flag(sym, NOT_NULL);
 }
 
 
-_Py_UopsSymbol *
-_Py_uop_sym_new_unknown(_Py_UOpsContext *ctx)
+JitOptSymbol *
+_Py_uop_sym_new_unknown(JitOptContext *ctx)
 {
-    return sym_new(ctx);
+    JitOptSymbol *res = sym_new(ctx);
+    if (res == NULL) {
+        return out_of_space(ctx);
+    }
+    return res;
 }
 
-_Py_UopsSymbol *
-_Py_uop_sym_new_not_null(_Py_UOpsContext *ctx)
+JitOptSymbol *
+_Py_uop_sym_new_not_null(JitOptContext *ctx)
 {
-    _Py_UopsSymbol *res = _Py_uop_sym_new_unknown(ctx);
+    JitOptSymbol *res = sym_new(ctx);
     if (res == NULL) {
         return out_of_space(ctx);
     }
-    sym_set_flag(res, NOT_NULL);
+    res->tag = JIT_SYM_NON_NULL_TAG;
     return res;
 }
 
-_Py_UopsSymbol *
-_Py_uop_sym_new_type(_Py_UOpsContext *ctx, PyTypeObject *typ)
+JitOptSymbol *
+_Py_uop_sym_new_type(JitOptContext *ctx, PyTypeObject *typ)
 {
-    _Py_UopsSymbol *res = sym_new(ctx);
+    JitOptSymbol *res = sym_new(ctx);
     if (res == NULL) {
         return out_of_space(ctx);
     }
@@ -237,11 +299,11 @@ _Py_uop_sym_new_type(_Py_UOpsContext *ctx, PyTypeObject 
*typ)
 }
 
 // Adds a new reference to const_val, owned by the symbol.
-_Py_UopsSymbol *
-_Py_uop_sym_new_const(_Py_UOpsContext *ctx, PyObject *const_val)
+JitOptSymbol *
+_Py_uop_sym_new_const(JitOptContext *ctx, PyObject *const_val)
 {
     assert(const_val != NULL);
-    _Py_UopsSymbol *res = sym_new(ctx);
+    JitOptSymbol *res = sym_new(ctx);
     if (res == NULL) {
         return out_of_space(ctx);
     }
@@ -249,10 +311,10 @@ _Py_uop_sym_new_const(_Py_UOpsContext *ctx, PyObject 
*const_val)
     return res;
 }
 
-_Py_UopsSymbol *
-_Py_uop_sym_new_null(_Py_UOpsContext *ctx)
+JitOptSymbol *
+_Py_uop_sym_new_null(JitOptContext *ctx)
 {
-    _Py_UopsSymbol *null_sym = _Py_uop_sym_new_unknown(ctx);
+    JitOptSymbol *null_sym = sym_new(ctx);
     if (null_sym == NULL) {
         return out_of_space(ctx);
     }
@@ -261,64 +323,105 @@ _Py_uop_sym_new_null(_Py_UOpsContext *ctx)
 }
 
 PyTypeObject *
-_Py_uop_sym_get_type(_Py_UopsSymbol *sym)
+_Py_uop_sym_get_type(JitOptSymbol *sym)
 {
-    if (_Py_uop_sym_is_bottom(sym)) {
-        return NULL;
-    }
-    return sym->typ;
+    JitSymType tag = sym->tag;
+    switch(tag) {
+        case JIT_SYM_NULL_TAG:
+        case JIT_SYM_TYPE_VERSION_TAG:
+        case JIT_SYM_BOTTOM_TAG:
+        case JIT_SYM_NON_NULL_TAG:
+        case JIT_SYM_UNKNOWN_TAG:
+            return NULL;
+        case JIT_SYM_KNOWN_CLASS_TAG:
+            return sym->cls.type;
+        case JIT_SYM_KNOWN_VALUE_TAG:
+            return Py_TYPE(sym->value.value);
+        case JIT_SYM_TUPLE_TAG:
+            return &PyTuple_Type;
+    }
+    Py_UNREACHABLE();
 }
 
 unsigned int
-_Py_uop_sym_get_type_version(_Py_UopsSymbol *sym)
+_Py_uop_sym_get_type_version(JitOptSymbol *sym)
 {
-    return sym->type_version;
+    JitSymType tag = sym->tag;
+    switch(tag) {
+        case JIT_SYM_NULL_TAG:
+        case JIT_SYM_BOTTOM_TAG:
+        case JIT_SYM_NON_NULL_TAG:
+        case JIT_SYM_UNKNOWN_TAG:
+            return 0;
+        case JIT_SYM_TYPE_VERSION_TAG:
+            return sym->version.version;
+        case JIT_SYM_KNOWN_CLASS_TAG:
+            return sym->cls.version;
+        case JIT_SYM_KNOWN_VALUE_TAG:
+            return Py_TYPE(sym->value.value)->tp_version_tag;
+        case JIT_SYM_TUPLE_TAG:
+            return PyTuple_Type.tp_version_tag;
+    }
+    Py_UNREACHABLE();
 }
 
 bool
-_Py_uop_sym_has_type(_Py_UopsSymbol *sym)
+_Py_uop_sym_has_type(JitOptSymbol *sym)
 {
-    if (_Py_uop_sym_is_bottom(sym)) {
-        return false;
-    }
-    return sym->typ != NULL;
+    JitSymType tag = sym->tag;
+    switch(tag) {
+        case JIT_SYM_NULL_TAG:
+        case JIT_SYM_TYPE_VERSION_TAG:
+        case JIT_SYM_BOTTOM_TAG:
+        case JIT_SYM_NON_NULL_TAG:
+        case JIT_SYM_UNKNOWN_TAG:
+            return false;
+        case JIT_SYM_KNOWN_CLASS_TAG:
+        case JIT_SYM_KNOWN_VALUE_TAG:
+        case JIT_SYM_TUPLE_TAG:
+            return true;
+    }
+    Py_UNREACHABLE();
 }
 
 bool
-_Py_uop_sym_matches_type(_Py_UopsSymbol *sym, PyTypeObject *typ)
+_Py_uop_sym_matches_type(JitOptSymbol *sym, PyTypeObject *typ)
 {
     assert(typ != NULL && PyType_Check(typ));
     return _Py_uop_sym_get_type(sym) == typ;
 }
 
 bool
-_Py_uop_sym_matches_type_version(_Py_UopsSymbol *sym, unsigned int version)
+_Py_uop_sym_matches_type_version(JitOptSymbol *sym, unsigned int version)
 {
     return _Py_uop_sym_get_type_version(sym) == version;
 }
 
-
 int
-_Py_uop_sym_truthiness(_Py_UopsSymbol *sym)
-{
-    /* There are some non-constant values for
-     * which `bool(val)` always evaluates to
-     * True or False, such as tuples with known
-     * length, but unknown contents, or bound-methods.
-     * This function will need updating
-     * should we support those values.
-     */
-    if (_Py_uop_sym_is_bottom(sym)) {
-        return -1;
-    }
-    if (!_Py_uop_sym_is_const(sym)) {
-        return -1;
-    }
-    PyObject *value = _Py_uop_sym_get_const(sym);
+_Py_uop_sym_truthiness(JitOptSymbol *sym)
+{
+    switch(sym->tag) {
+        case JIT_SYM_NULL_TAG:
+        case JIT_SYM_TYPE_VERSION_TAG:
+        case JIT_SYM_BOTTOM_TAG:
+        case JIT_SYM_NON_NULL_TAG:
+        case JIT_SYM_UNKNOWN_TAG:
+            return -1;
+        case JIT_SYM_KNOWN_CLASS_TAG:
+            /* TODO :
+             * Instances of some classes are always
+             * true. We should return 1 in those cases */
+            return -1;
+        case JIT_SYM_KNOWN_VALUE_TAG:
+            break;
+        case JIT_SYM_TUPLE_TAG:
+            return sym->tuple.length != 0;
+    }
+    PyObject *value = sym->value.value;
+    /* Only handle a few known safe types */
     if (value == Py_None) {
         return 0;
     }
-    /* Only handle a few known safe types */
     PyTypeObject *tp = Py_TYPE(value);
     if (tp == &PyLong_Type) {
         return !_PyLong_IsZero((PyLongObject *)value);
@@ -332,13 +435,84 @@ _Py_uop_sym_truthiness(_Py_UopsSymbol *sym)
     return -1;
 }
 
+static JitOptSymbol *
+allocation_base(JitOptContext *ctx)
+{
+    return ctx->t_arena.arena;
+}
+
+JitOptSymbol *
+_Py_uop_sym_new_tuple(JitOptContext *ctx, int size, JitOptSymbol **args)
+{
+    JitOptSymbol *res = sym_new(ctx);
+    if (res == NULL) {
+        return out_of_space(ctx);
+    }
+    if (size > MAX_SYMBOLIC_TUPLE_SIZE) {
+        res->tag = JIT_SYM_KNOWN_CLASS_TAG;
+        res->cls.type = &PyTuple_Type;
+    }
+    else {
+        res->tag = JIT_SYM_TUPLE_TAG;
+        res->tuple.length = size;
+        for (int i = 0; i < size; i++) {
+            res->tuple.items[i] = (uint16_t)(args[i] - allocation_base(ctx));
+        }
+    }
+    return res;
+}
+
+JitOptSymbol *
+_Py_uop_sym_tuple_getitem(JitOptContext *ctx, JitOptSymbol *sym, int item)
+{
+    assert(item >= 0);
+    if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) {
+        PyObject *tuple = sym->value.value;
+        if (PyTuple_CheckExact(tuple) && item < PyTuple_GET_SIZE(tuple)) {
+            return _Py_uop_sym_new_const(ctx, PyTuple_GET_ITEM(tuple, item));
+        }
+    }
+    else if (sym->tag == JIT_SYM_TUPLE_TAG && item < sym->tuple.length) {
+        return allocation_base(ctx) + sym->tuple.items[item];
+    }
+    return _Py_uop_sym_new_unknown(ctx);
+}
+
+int
+_Py_uop_sym_tuple_length(JitOptSymbol *sym)
+{
+    if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) {
+        PyObject *tuple = sym->value.value;
+        if (PyTuple_CheckExact(tuple)) {
+            return PyTuple_GET_SIZE(tuple);
+        }
+    }
+    else if (sym->tag == JIT_SYM_TUPLE_TAG) {
+        return sym->tuple.length;
+    }
+    return -1;
+}
+
+// Return true if known to be immortal.
+bool
+_Py_uop_sym_is_immortal(JitOptSymbol *sym)
+{
+    if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) {
+        return _Py_IsImmortal(sym->value.value);
+    }
+    if (sym->tag == JIT_SYM_KNOWN_CLASS_TAG) {
+        return sym->cls.type == &PyBool_Type;
+    }
+    return false;
+}
+
 // 0 on success, -1 on error.
 _Py_UOpsAbstractFrame *
 _Py_uop_frame_new(
-    _Py_UOpsContext *ctx,
+    JitOptContext *ctx,
     PyCodeObject *co,
     int curr_stackentries,
-    _Py_UopsSymbol **args,
+    JitOptSymbol **args,
     int arg_len)
 {
     assert(ctx->curr_frame_depth < MAX_ABSTRACT_FRAME_DEPTH);
@@ -363,14 +537,14 @@ _Py_uop_frame_new(
     }
 
     for (int i = arg_len; i < co->co_nlocalsplus; i++) {
-        _Py_UopsSymbol *local = _Py_uop_sym_new_unknown(ctx);
+        JitOptSymbol *local = _Py_uop_sym_new_unknown(ctx);
         frame->locals[i] = local;
     }
 
 
     // Initialize the stack as well
     for (int i = 0; i < curr_stackentries; i++) {
-        _Py_UopsSymbol *stackvar = _Py_uop_sym_new_unknown(ctx);
+        JitOptSymbol *stackvar = _Py_uop_sym_new_unknown(ctx);
         frame->stack[i] = stackvar;
     }
 
@@ -378,7 +552,7 @@ _Py_uop_frame_new(
 }
 
 void
-_Py_uop_abstractcontext_fini(_Py_UOpsContext *ctx)
+_Py_uop_abstractcontext_fini(JitOptContext *ctx)
 {
     if (ctx == NULL) {
         return;
@@ -386,13 +560,17 @@ _Py_uop_abstractcontext_fini(_Py_UOpsContext *ctx)
     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);
+        JitOptSymbol *sym = &ctx->t_arena.arena[i];
+        if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) {
+            Py_CLEAR(sym->value.value);
+        }
     }
 }
 
 void
-_Py_uop_abstractcontext_init(_Py_UOpsContext *ctx)
+_Py_uop_abstractcontext_init(JitOptContext *ctx)
 {
+    static_assert(sizeof(JitOptSymbol) <= 2*sizeof(uint64_t));
     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.
@@ -410,7 +588,7 @@ _Py_uop_abstractcontext_init(_Py_UOpsContext *ctx)
 }
 
 int
-_Py_uop_frame_pop(_Py_UOpsContext *ctx)
+_Py_uop_frame_pop(JitOptContext *ctx)
 {
     _Py_UOpsAbstractFrame *frame = ctx->frame;
     ctx->n_consumed = frame->locals;
@@ -431,26 +609,25 @@ do { \
     } \
 } while (0)
 
-static _Py_UopsSymbol *
-make_bottom(_Py_UOpsContext *ctx)
+static JitOptSymbol *
+make_bottom(JitOptContext *ctx)
 {
-    _Py_UopsSymbol *sym = _Py_uop_sym_new_unknown(ctx);
-    _Py_uop_sym_set_null(ctx, sym);
-    _Py_uop_sym_set_non_null(ctx, sym);
+    JitOptSymbol *sym = sym_new(ctx);
+    sym->tag = JIT_SYM_BOTTOM_TAG;
     return sym;
 }
 
 PyObject *
 _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
 {
-    _Py_UOpsContext context;
-    _Py_UOpsContext *ctx = &context;
+    JitOptContext context;
+    JitOptContext *ctx = &context;
     _Py_uop_abstractcontext_init(ctx);
     PyObject *val_42 = NULL;
     PyObject *val_43 = NULL;
 
     // Use a single 'sym' variable so copy-pasting tests is easier.
-    _Py_UopsSymbol *sym = _Py_uop_sym_new_unknown(ctx);
+    JitOptSymbol *sym = _Py_uop_sym_new_unknown(ctx);
     if (sym == NULL) {
         goto fail;
     }
@@ -510,6 +687,7 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject 
*Py_UNUSED(ignored))
     TEST_PREDICATE(_Py_uop_sym_is_const(sym), "42 is not a constant");
     TEST_PREDICATE(_Py_uop_sym_get_const(sym) != NULL, "42 as constant is 
NULL");
     TEST_PREDICATE(_Py_uop_sym_get_const(sym) == val_42, "42 as constant isn't 
42");
+    TEST_PREDICATE(_Py_uop_sym_is_immortal(sym), "42 is not immortal");
 
     _Py_uop_sym_set_type(ctx, sym, &PyLong_Type);  // Should be a no-op
     TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "(42 and 42) 
isn't an int");
@@ -518,6 +696,9 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject 
*Py_UNUSED(ignored))
     _Py_uop_sym_set_type(ctx, sym, &PyFloat_Type);  // Should make it bottom
     TEST_PREDICATE(_Py_uop_sym_is_bottom(sym), "(42 and float) isn't bottom");
 
+    sym = _Py_uop_sym_new_type(ctx, &PyBool_Type);
+    TEST_PREDICATE(_Py_uop_sym_is_immortal(sym), "a bool is not immortal");
+
     sym = _Py_uop_sym_new_type(ctx, &PyLong_Type);
     if (sym == NULL) {
         goto fail;
@@ -534,15 +715,37 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject 
*Py_UNUSED(ignored))
     sym = _Py_uop_sym_new_const(ctx, PyLong_FromLong(0));
     TEST_PREDICATE(_Py_uop_sym_truthiness(sym) == 0, "bool(0) is not False");
 
+    JitOptSymbol *i1 = _Py_uop_sym_new_type(ctx, &PyFloat_Type);
+    JitOptSymbol *i2 = _Py_uop_sym_new_const(ctx, val_43);
+    JitOptSymbol *array[2] = { i1, i2 };
+    sym = _Py_uop_sym_new_tuple(ctx, 2, array);
+    TEST_PREDICATE(
+        _Py_uop_sym_matches_type(_Py_uop_sym_tuple_getitem(ctx, sym, 0), 
&PyFloat_Type),
+        "tuple item does not match value used to create tuple"
+    );
+    TEST_PREDICATE(
+        _Py_uop_sym_get_const(_Py_uop_sym_tuple_getitem(ctx, sym, 1)) == 
val_43,
+        "tuple item does not match value used to create tuple"
+    );
+    PyObject *pair[2] = { val_42, val_43 };
+    PyObject *tuple = _PyTuple_FromArray(pair, 2);
+    sym = _Py_uop_sym_new_const(ctx, tuple);
+    TEST_PREDICATE(
+        _Py_uop_sym_get_const(_Py_uop_sym_tuple_getitem(ctx, sym, 1)) == 
val_43,
+        "tuple item does not match value used to create tuple"
+    );
+
     _Py_uop_abstractcontext_fini(ctx);
     Py_DECREF(val_42);
     Py_DECREF(val_43);
+    Py_DECREF(tuple);
     Py_RETURN_NONE;
 
 fail:
     _Py_uop_abstractcontext_fini(ctx);
     Py_XDECREF(val_42);
     Py_XDECREF(val_43);
+    Py_DECREF(tuple);
     return NULL;
 }
 
diff --git a/Tools/cases_generator/optimizer_generator.py 
b/Tools/cases_generator/optimizer_generator.py
index 2928440fecca0c..5cfec4bfecbf07 100644
--- a/Tools/cases_generator/optimizer_generator.py
+++ b/Tools/cases_generator/optimizer_generator.py
@@ -36,10 +36,10 @@ def validate_uop(override: Uop, uop: Uop) -> None:
 
 def type_name(var: StackItem) -> str:
     if var.is_array():
-        return f"_Py_UopsSymbol **"
+        return f"JitOptSymbol **"
     if var.type:
         return var.type
-    return f"_Py_UopsSymbol *"
+    return f"JitOptSymbol *"
 
 
 def declare_variables(uop: Uop, out: CWriter, skip_inputs: bool) -> None:
@@ -151,11 +151,11 @@ def write_uop(
                 var.defined = False
             storage = emitter.emit_tokens(override, storage, None)
             out.start_line()
-            storage.flush(out, cast_type="_Py_UopsSymbol *")
+            storage.flush(out, cast_type="JitOptSymbol *")
         else:
             emit_default(out, uop, stack)
             out.start_line()
-            stack.flush(out, cast_type="_Py_UopsSymbol *")
+            stack.flush(out, cast_type="JitOptSymbol *")
     except StackError as ex:
         raise analysis_error(ex.args[0], prototype.body[0]) # from None
 

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to