[Python-checkins] gh-107557: Setup abstract interpretation (#107847)

Fidget-Spinner webhook-mailer at python.org
Tue Aug 15 14:55:35 EDT 2023


https://github.com/python/cpython/commit/e28b0dc86dd1d058788b9e1eaa825cdfc2d97067
commit: e28b0dc86dd1d058788b9e1eaa825cdfc2d97067
branch: main
author: Ken Jin <kenjin at python.org>
committer: Fidget-Spinner <kenjin at python.org>
date: 2023-08-15T18:04:17Z
summary:

gh-107557: Setup abstract interpretation (#107847)

Co-authored-by: Guido van Rossum <gvanrossum at users.noreply.github.com>
Co-authored-by: Jules <57632293+juliapoo at users.noreply.github.com>

files:
A Include/internal/pycore_optimizer.h
A Misc/NEWS.d/next/Core and Builtins/2023-08-02-09-55-21.gh-issue-107557.P1z-in.rst
A Python/abstract_interp_cases.c.h
A Python/optimizer_analysis.c
M .gitattributes
M Include/cpython/optimizer.h
M Include/internal/pycore_opcode_metadata.h
M Include/internal/pycore_uops.h
M Makefile.pre.in
M PCbuild/_freeze_module.vcxproj
M PCbuild/_freeze_module.vcxproj.filters
M PCbuild/pythoncore.vcxproj
M PCbuild/pythoncore.vcxproj.filters
M Python/bytecodes.c
M Python/executor_cases.c.h
M Python/optimizer.c
M Tools/c-analyzer/cpython/_parser.py
M Tools/c-analyzer/cpython/ignored.tsv
M Tools/cases_generator/generate_cases.py
M Tools/cases_generator/instructions.py
M Tools/cases_generator/stacking.py

diff --git a/.gitattributes b/.gitattributes
index 4a072bc990f0f..317a613217a9b 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -90,6 +90,7 @@ Programs/test_frozenmain.h                          generated
 Python/Python-ast.c                                 generated
 Python/executor_cases.c.h                           generated
 Python/generated_cases.c.h                          generated
+Python/abstract_interp_cases.c.h                    generated
 Python/opcode_targets.h                             generated
 Python/stdlib_module_names.h                        generated
 Tools/peg_generator/pegen/grammar_parser.py         generated
diff --git a/Include/cpython/optimizer.h b/Include/cpython/optimizer.h
index da34ec1882a53..e3fe0e8f0ffd5 100644
--- a/Include/cpython/optimizer.h
+++ b/Include/cpython/optimizer.h
@@ -22,7 +22,7 @@ typedef struct _PyExecutorObject {
 typedef struct _PyOptimizerObject _PyOptimizerObject;
 
 /* Should return > 0 if a new executor is created. O if no executor is produced and < 0 if an error occurred. */
-typedef int (*optimize_func)(_PyOptimizerObject* self, PyCodeObject *code, _Py_CODEUNIT *instr, _PyExecutorObject **);
+typedef int (*optimize_func)(_PyOptimizerObject* self, PyCodeObject *code, _Py_CODEUNIT *instr, _PyExecutorObject **, int curr_stackentries);
 
 typedef struct _PyOptimizerObject {
     PyObject_HEAD
diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h
index c0a2e9d91c4f4..df9b4184e2a50 100644
--- a/Include/internal/pycore_opcode_metadata.h
+++ b/Include/internal/pycore_opcode_metadata.h
@@ -55,6 +55,7 @@
 #define _POP_JUMP_IF_FALSE 331
 #define _POP_JUMP_IF_TRUE 332
 #define JUMP_TO_TOP 333
+#define INSERT 334
 
 extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump);
 #ifdef NEED_OPCODE_METADATA
@@ -118,18 +119,38 @@ int _PyOpcode_num_popped(int opcode, int oparg, bool jump)  {
             return 1;
         case UNARY_INVERT:
             return 1;
+        case _GUARD_BOTH_INT:
+            return 2;
+        case _BINARY_OP_MULTIPLY_INT:
+            return 2;
+        case _BINARY_OP_ADD_INT:
+            return 2;
+        case _BINARY_OP_SUBTRACT_INT:
+            return 2;
         case BINARY_OP_MULTIPLY_INT:
             return 2;
         case BINARY_OP_ADD_INT:
             return 2;
         case BINARY_OP_SUBTRACT_INT:
             return 2;
+        case _GUARD_BOTH_FLOAT:
+            return 2;
+        case _BINARY_OP_MULTIPLY_FLOAT:
+            return 2;
+        case _BINARY_OP_ADD_FLOAT:
+            return 2;
+        case _BINARY_OP_SUBTRACT_FLOAT:
+            return 2;
         case BINARY_OP_MULTIPLY_FLOAT:
             return 2;
         case BINARY_OP_ADD_FLOAT:
             return 2;
         case BINARY_OP_SUBTRACT_FLOAT:
             return 2;
+        case _GUARD_BOTH_UNICODE:
+            return 2;
+        case _BINARY_OP_ADD_UNICODE:
+            return 2;
         case BINARY_OP_ADD_UNICODE:
             return 2;
         case BINARY_OP_INPLACE_ADD_UNICODE:
@@ -226,14 +247,26 @@ int _PyOpcode_num_popped(int opcode, int oparg, bool jump)  {
             return 1;
         case DELETE_GLOBAL:
             return 0;
+        case _LOAD_LOCALS:
+            return 0;
         case LOAD_LOCALS:
             return 0;
+        case _LOAD_FROM_DICT_OR_GLOBALS:
+            return 1;
         case LOAD_NAME:
             return 0;
         case LOAD_FROM_DICT_OR_GLOBALS:
             return 1;
         case LOAD_GLOBAL:
             return 0;
+        case _GUARD_GLOBALS_VERSION:
+            return 0;
+        case _GUARD_BUILTINS_VERSION:
+            return 0;
+        case _LOAD_GLOBAL_MODULE:
+            return 0;
+        case _LOAD_GLOBAL_BUILTINS:
+            return 0;
         case LOAD_GLOBAL_MODULE:
             return 0;
         case LOAD_GLOBAL_BUILTIN:
@@ -294,6 +327,12 @@ int _PyOpcode_num_popped(int opcode, int oparg, bool jump)  {
             return 1;
         case LOAD_METHOD:
             return 1;
+        case _GUARD_TYPE_VERSION:
+            return 1;
+        case _CHECK_MANAGED_OBJECT_HAS_VALUES:
+            return 1;
+        case _LOAD_ATTR_INSTANCE_VALUE:
+            return 1;
         case LOAD_ATTR_INSTANCE_VALUE:
             return 1;
         case LOAD_ATTR_MODULE:
@@ -348,6 +387,8 @@ int _PyOpcode_num_popped(int opcode, int oparg, bool jump)  {
             return 1;
         case POP_JUMP_IF_TRUE:
             return 1;
+        case IS_NONE:
+            return 1;
         case POP_JUMP_IF_NONE:
             return 1;
         case POP_JUMP_IF_NOT_NONE:
@@ -372,10 +413,28 @@ int _PyOpcode_num_popped(int opcode, int oparg, bool jump)  {
             return 1;
         case INSTRUMENTED_FOR_ITER:
             return 0;
+        case _ITER_CHECK_LIST:
+            return 1;
+        case _IS_ITER_EXHAUSTED_LIST:
+            return 1;
+        case _ITER_NEXT_LIST:
+            return 1;
         case FOR_ITER_LIST:
             return 1;
+        case _ITER_CHECK_TUPLE:
+            return 1;
+        case _IS_ITER_EXHAUSTED_TUPLE:
+            return 1;
+        case _ITER_NEXT_TUPLE:
+            return 1;
         case FOR_ITER_TUPLE:
             return 1;
+        case _ITER_CHECK_RANGE:
+            return 1;
+        case _IS_ITER_EXHAUSTED_RANGE:
+            return 1;
+        case _ITER_NEXT_RANGE:
+            return 1;
         case FOR_ITER_RANGE:
             return 1;
         case FOR_ITER_GEN:
@@ -494,6 +553,18 @@ int _PyOpcode_num_popped(int opcode, int oparg, bool jump)  {
             return 0;
         case RESERVED:
             return 0;
+        case _POP_JUMP_IF_FALSE:
+            return 1;
+        case _POP_JUMP_IF_TRUE:
+            return 1;
+        case JUMP_TO_TOP:
+            return 0;
+        case SAVE_IP:
+            return 0;
+        case EXIT_TRACE:
+            return 0;
+        case INSERT:
+            return oparg + 1;
         default:
             return -1;
     }
@@ -562,18 +633,38 @@ int _PyOpcode_num_pushed(int opcode, int oparg, bool jump)  {
             return 1;
         case UNARY_INVERT:
             return 1;
+        case _GUARD_BOTH_INT:
+            return 2;
+        case _BINARY_OP_MULTIPLY_INT:
+            return 1;
+        case _BINARY_OP_ADD_INT:
+            return 1;
+        case _BINARY_OP_SUBTRACT_INT:
+            return 1;
         case BINARY_OP_MULTIPLY_INT:
             return 1;
         case BINARY_OP_ADD_INT:
             return 1;
         case BINARY_OP_SUBTRACT_INT:
             return 1;
+        case _GUARD_BOTH_FLOAT:
+            return 2;
+        case _BINARY_OP_MULTIPLY_FLOAT:
+            return 1;
+        case _BINARY_OP_ADD_FLOAT:
+            return 1;
+        case _BINARY_OP_SUBTRACT_FLOAT:
+            return 1;
         case BINARY_OP_MULTIPLY_FLOAT:
             return 1;
         case BINARY_OP_ADD_FLOAT:
             return 1;
         case BINARY_OP_SUBTRACT_FLOAT:
             return 1;
+        case _GUARD_BOTH_UNICODE:
+            return 2;
+        case _BINARY_OP_ADD_UNICODE:
+            return 1;
         case BINARY_OP_ADD_UNICODE:
             return 1;
         case BINARY_OP_INPLACE_ADD_UNICODE:
@@ -670,14 +761,26 @@ int _PyOpcode_num_pushed(int opcode, int oparg, bool jump)  {
             return 0;
         case DELETE_GLOBAL:
             return 0;
+        case _LOAD_LOCALS:
+            return 1;
         case LOAD_LOCALS:
             return 1;
+        case _LOAD_FROM_DICT_OR_GLOBALS:
+            return 1;
         case LOAD_NAME:
             return 1;
         case LOAD_FROM_DICT_OR_GLOBALS:
             return 1;
         case LOAD_GLOBAL:
             return ((oparg & 1) ? 1 : 0) + 1;
+        case _GUARD_GLOBALS_VERSION:
+            return 0;
+        case _GUARD_BUILTINS_VERSION:
+            return 0;
+        case _LOAD_GLOBAL_MODULE:
+            return ((oparg & 1) ? 1 : 0) + 1;
+        case _LOAD_GLOBAL_BUILTINS:
+            return ((oparg & 1) ? 1 : 0) + 1;
         case LOAD_GLOBAL_MODULE:
             return (oparg & 1 ? 1 : 0) + 1;
         case LOAD_GLOBAL_BUILTIN:
@@ -738,6 +841,12 @@ int _PyOpcode_num_pushed(int opcode, int oparg, bool jump)  {
             return ((oparg & 1) ? 1 : 0) + 1;
         case LOAD_METHOD:
             return ((oparg & 1) ? 1 : 0) + 1;
+        case _GUARD_TYPE_VERSION:
+            return 1;
+        case _CHECK_MANAGED_OBJECT_HAS_VALUES:
+            return 1;
+        case _LOAD_ATTR_INSTANCE_VALUE:
+            return ((oparg & 1) ? 1 : 0) + 1;
         case LOAD_ATTR_INSTANCE_VALUE:
             return (oparg & 1 ? 1 : 0) + 1;
         case LOAD_ATTR_MODULE:
@@ -792,6 +901,8 @@ int _PyOpcode_num_pushed(int opcode, int oparg, bool jump)  {
             return 0;
         case POP_JUMP_IF_TRUE:
             return 0;
+        case IS_NONE:
+            return 1;
         case POP_JUMP_IF_NONE:
             return 0;
         case POP_JUMP_IF_NOT_NONE:
@@ -816,10 +927,28 @@ int _PyOpcode_num_pushed(int opcode, int oparg, bool jump)  {
             return 2;
         case INSTRUMENTED_FOR_ITER:
             return 0;
+        case _ITER_CHECK_LIST:
+            return 1;
+        case _IS_ITER_EXHAUSTED_LIST:
+            return 2;
+        case _ITER_NEXT_LIST:
+            return 2;
         case FOR_ITER_LIST:
             return 2;
+        case _ITER_CHECK_TUPLE:
+            return 1;
+        case _IS_ITER_EXHAUSTED_TUPLE:
+            return 2;
+        case _ITER_NEXT_TUPLE:
+            return 2;
         case FOR_ITER_TUPLE:
             return 2;
+        case _ITER_CHECK_RANGE:
+            return 1;
+        case _IS_ITER_EXHAUSTED_RANGE:
+            return 2;
+        case _ITER_NEXT_RANGE:
+            return 2;
         case FOR_ITER_RANGE:
             return 2;
         case FOR_ITER_GEN:
@@ -938,6 +1067,18 @@ int _PyOpcode_num_pushed(int opcode, int oparg, bool jump)  {
             return 0;
         case RESERVED:
             return 0;
+        case _POP_JUMP_IF_FALSE:
+            return 0;
+        case _POP_JUMP_IF_TRUE:
+            return 0;
+        case JUMP_TO_TOP:
+            return 0;
+        case SAVE_IP:
+            return 0;
+        case EXIT_TRACE:
+            return 0;
+        case INSERT:
+            return oparg + 1;
         default:
             return -1;
     }
@@ -1393,5 +1534,6 @@ const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = {
     [_POP_JUMP_IF_FALSE] = "_POP_JUMP_IF_FALSE",
     [_POP_JUMP_IF_TRUE] = "_POP_JUMP_IF_TRUE",
     [JUMP_TO_TOP] = "JUMP_TO_TOP",
+    [INSERT] = "INSERT",
 };
 #endif // NEED_OPCODE_METADATA
diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h
new file mode 100644
index 0000000000000..2ae657c4e117f
--- /dev/null
+++ b/Include/internal/pycore_optimizer.h
@@ -0,0 +1,20 @@
+#ifndef Py_INTERNAL_OPTIMIZER_H
+#define Py_INTERNAL_OPTIMIZER_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef Py_BUILD_CORE
+#  error "this header requires Py_BUILD_CORE define"
+#endif
+
+#include "pycore_uops.h"
+
+int _Py_uop_analyze_and_optimize(PyCodeObject *code,
+    _PyUOpInstruction *trace, int trace_len, int curr_stackentries);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_INTERNAL_OPTIMIZER_H */
diff --git a/Include/internal/pycore_uops.h b/Include/internal/pycore_uops.h
index 57a5970353b36..254eeca2361be 100644
--- a/Include/internal/pycore_uops.h
+++ b/Include/internal/pycore_uops.h
@@ -8,7 +8,7 @@ extern "C" {
 #  error "this header requires Py_BUILD_CORE define"
 #endif
 
-#define _Py_UOP_MAX_TRACE_LENGTH 32
+#define _Py_UOP_MAX_TRACE_LENGTH 64
 
 typedef struct {
     uint32_t opcode;
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 3a628bf49e97c..32d928316f221 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -405,6 +405,7 @@ PYTHON_OBJS=	\
 		Python/mysnprintf.o \
 		Python/mystrtoul.o \
 		Python/optimizer.o \
+		Python/optimizer_analysis.o \
 		Python/pathconfig.o \
 		Python/preconfig.o \
 		Python/pyarena.o \
@@ -1552,10 +1553,12 @@ regen-cases:
 		-m $(srcdir)/Include/internal/pycore_opcode_metadata.h.new \
 		-e $(srcdir)/Python/executor_cases.c.h.new \
 		-p $(srcdir)/Lib/_opcode_metadata.py.new \
+		-a $(srcdir)/Python/abstract_interp_cases.c.h.new \
 		$(srcdir)/Python/bytecodes.c
 	$(UPDATE_FILE) $(srcdir)/Python/generated_cases.c.h $(srcdir)/Python/generated_cases.c.h.new
 	$(UPDATE_FILE) $(srcdir)/Include/internal/pycore_opcode_metadata.h $(srcdir)/Include/internal/pycore_opcode_metadata.h.new
 	$(UPDATE_FILE) $(srcdir)/Python/executor_cases.c.h $(srcdir)/Python/executor_cases.c.h.new
+	$(UPDATE_FILE) $(srcdir)/Python/abstract_interp_cases.c.h $(srcdir)/Python/abstract_interp_cases.c.h.new
 	$(UPDATE_FILE) $(srcdir)/Lib/_opcode_metadata.py $(srcdir)/Lib/_opcode_metadata.py.new
 
 Python/compile.o: $(srcdir)/Include/internal/pycore_opcode_metadata.h
@@ -1568,6 +1571,7 @@ Python/ceval.o: \
 
 Python/executor.o: \
 		$(srcdir)/Include/internal/pycore_opcode_metadata.h \
+		$(srcdir)/Include/internal/pycore_optimizer.h \
 		$(srcdir)/Python/ceval_macros.h \
 		$(srcdir)/Python/executor_cases.c.h
 
@@ -1576,7 +1580,12 @@ Python/flowgraph.o: \
 
 Python/optimizer.o: \
 		$(srcdir)/Python/executor_cases.c.h \
-		$(srcdir)/Include/internal/pycore_opcode_metadata.h
+		$(srcdir)/Include/internal/pycore_opcode_metadata.h \
+		$(srcdir)/Include/internal/pycore_optimizer.h
+
+Python/optimizer_analysis.o: \
+		$(srcdir)/Include/internal/pycore_opcode_metadata.h \
+		$(srcdir)/Include/internal/pycore_optimizer.h
 
 Python/frozen.o: $(FROZEN_FILES_OUT)
 
@@ -1786,6 +1795,7 @@ PYTHON_HEADERS= \
 		$(srcdir)/Include/internal/pycore_obmalloc_init.h \
 		$(srcdir)/Include/internal/pycore_opcode.h \
 		$(srcdir)/Include/internal/pycore_opcode_utils.h \
+		$(srcdir)/Include/internal/pycore_optimizer.h \
 		$(srcdir)/Include/internal/pycore_pathconfig.h \
 		$(srcdir)/Include/internal/pycore_pyarena.h \
 		$(srcdir)/Include/internal/pycore_pyerrors.h \
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-02-09-55-21.gh-issue-107557.P1z-in.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-02-09-55-21.gh-issue-107557.P1z-in.rst
new file mode 100644
index 0000000000000..392f59c79e8de
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-08-02-09-55-21.gh-issue-107557.P1z-in.rst	
@@ -0,0 +1 @@
+Generate the cases needed for the barebones tier 2 abstract interpreter for optimization passes in CPython.
diff --git a/PCbuild/_freeze_module.vcxproj b/PCbuild/_freeze_module.vcxproj
index e247637a0dfe5..bdcf29ba44dab 100644
--- a/PCbuild/_freeze_module.vcxproj
+++ b/PCbuild/_freeze_module.vcxproj
@@ -218,6 +218,7 @@
     <ClCompile Include="..\Python\mysnprintf.c" />
     <ClCompile Include="..\Python\mystrtoul.c" />
     <ClCompile Include="..\Python\optimizer.c" />
+    <ClCompile Include="..\Python\optimizer_analysis.c" />
     <ClCompile Include="..\Python\pathconfig.c" />
     <ClCompile Include="..\Python\perf_trampoline.c" />
     <ClCompile Include="..\Python\preconfig.c" />
diff --git a/PCbuild/_freeze_module.vcxproj.filters b/PCbuild/_freeze_module.vcxproj.filters
index 2a0e009308022..45333fa97f1c6 100644
--- a/PCbuild/_freeze_module.vcxproj.filters
+++ b/PCbuild/_freeze_module.vcxproj.filters
@@ -283,6 +283,9 @@
     <ClCompile Include="..\Python\optimizer.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\Python\optimizer_analysis.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
     <ClCompile Include="..\Parser\parser.c">
       <Filter>Source Files</Filter>
     </ClCompile>
diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj
index bfe59acf12a69..b0e62864421e1 100644
--- a/PCbuild/pythoncore.vcxproj
+++ b/PCbuild/pythoncore.vcxproj
@@ -248,6 +248,7 @@
     <ClInclude Include="..\Include\internal\pycore_object_state.h" />
     <ClInclude Include="..\Include\internal\pycore_obmalloc.h" />
     <ClInclude Include="..\Include\internal\pycore_obmalloc_init.h" />
+    <ClInclude Include="..\Include\internal\pycore_optimizer.h" />    
     <ClInclude Include="..\Include\internal\pycore_pathconfig.h" />
     <ClInclude Include="..\Include\internal\pycore_pyarena.h" />
     <ClInclude Include="..\Include\internal\pycore_pyerrors.h" />
@@ -279,6 +280,7 @@
     <ClInclude Include="..\Include\internal\pycore_unionobject.h" />
     <ClInclude Include="..\Include\internal\pycore_unicodeobject.h" />
     <ClInclude Include="..\Include\internal\pycore_unicodeobject_generated.h" />
+    <ClInclude Include="..\Include\internal\pycore_uops.h" />    
     <ClInclude Include="..\Include\internal\pycore_warnings.h" />
     <ClInclude Include="..\Include\internal\pycore_weakref.h" />
     <ClInclude Include="..\Include\interpreteridobject.h" />
@@ -548,6 +550,7 @@
     <ClCompile Include="..\Python\mysnprintf.c" />
     <ClCompile Include="..\Python\mystrtoul.c" />
     <ClCompile Include="..\Python\optimizer.c" />
+    <ClCompile Include="..\Python\optimizer_analysis.c" />
     <ClCompile Include="..\Python\pathconfig.c" />
     <ClCompile Include="..\Python\perf_trampoline.c" />
     <ClCompile Include="..\Python\preconfig.c" />
diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters
index 0a8b0c3faf51e..d5f61e9c5d7c8 100644
--- a/PCbuild/pythoncore.vcxproj.filters
+++ b/PCbuild/pythoncore.vcxproj.filters
@@ -648,6 +648,9 @@
     <ClInclude Include="..\Include\internal\pycore_obmalloc_init.h">
       <Filter>Include\internal</Filter>
     </ClInclude>
+    <ClInclude Include="..\Include\internal\pycore_optimizer.h">
+      <Filter>Include\internal</Filter>
+    </ClInclude>    
     <ClInclude Include="..\Include\internal\pycore_pathconfig.h">
       <Filter>Include\internal</Filter>
     </ClInclude>
@@ -732,6 +735,9 @@
     <ClInclude Include="..\Include\internal\pycore_unionobject.h">
       <Filter>Include\internal</Filter>
     </ClInclude>
+    <ClInclude Include="..\Include\internal\pycore_uops.h">
+      <Filter>Include\internal</Filter>
+    </ClInclude>    
     <ClInclude Include="$(zlibDir)\crc32.h">
       <Filter>Modules\zlib</Filter>
     </ClInclude>
@@ -1223,6 +1229,9 @@
     <ClCompile Include="..\Python\optimizer.c">
       <Filter>Python</Filter>
     </ClCompile>
+    <ClCompile Include="..\Python\optimizer_analysis.c">
+      <Filter>Python</Filter>
+    </ClCompile>
     <ClCompile Include="..\Python\pathconfig.c">
       <Filter>Python</Filter>
     </ClCompile>
diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h
new file mode 100644
index 0000000000000..6bfcf534646b1
--- /dev/null
+++ b/Python/abstract_interp_cases.c.h
@@ -0,0 +1,761 @@
+// This file is generated by Tools/cases_generator/generate_cases.py
+// from:
+//   Python/bytecodes.c
+// Do not edit!
+
+        case NOP: {
+            break;
+        }
+
+        case POP_TOP: {
+            STACK_SHRINK(1);
+            break;
+        }
+
+        case PUSH_NULL: {
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case END_SEND: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case UNARY_NEGATIVE: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case UNARY_NOT: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case TO_BOOL: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case TO_BOOL_BOOL: {
+            break;
+        }
+
+        case TO_BOOL_INT: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case TO_BOOL_LIST: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case TO_BOOL_NONE: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case TO_BOOL_STR: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case TO_BOOL_ALWAYS_TRUE: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case UNARY_INVERT: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case _GUARD_BOTH_INT: {
+            break;
+        }
+
+        case _GUARD_BOTH_FLOAT: {
+            break;
+        }
+
+        case _BINARY_OP_MULTIPLY_FLOAT: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case _BINARY_OP_ADD_FLOAT: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case _BINARY_OP_SUBTRACT_FLOAT: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case _GUARD_BOTH_UNICODE: {
+            break;
+        }
+
+        case _BINARY_OP_ADD_UNICODE: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case BINARY_SUBSCR: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case BINARY_SLICE: {
+            STACK_SHRINK(2);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case STORE_SLICE: {
+            STACK_SHRINK(4);
+            break;
+        }
+
+        case BINARY_SUBSCR_LIST_INT: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case BINARY_SUBSCR_STR_INT: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case BINARY_SUBSCR_TUPLE_INT: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case BINARY_SUBSCR_DICT: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case LIST_APPEND: {
+            STACK_SHRINK(1);
+            break;
+        }
+
+        case SET_ADD: {
+            STACK_SHRINK(1);
+            break;
+        }
+
+        case STORE_SUBSCR: {
+            STACK_SHRINK(3);
+            break;
+        }
+
+        case STORE_SUBSCR_LIST_INT: {
+            STACK_SHRINK(3);
+            break;
+        }
+
+        case STORE_SUBSCR_DICT: {
+            STACK_SHRINK(3);
+            break;
+        }
+
+        case DELETE_SUBSCR: {
+            STACK_SHRINK(2);
+            break;
+        }
+
+        case CALL_INTRINSIC_1: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case CALL_INTRINSIC_2: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case GET_AITER: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case GET_ANEXT: {
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case GET_AWAITABLE: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case POP_EXCEPT: {
+            STACK_SHRINK(1);
+            break;
+        }
+
+        case LOAD_ASSERTION_ERROR: {
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case LOAD_BUILD_CLASS: {
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case STORE_NAME: {
+            STACK_SHRINK(1);
+            break;
+        }
+
+        case DELETE_NAME: {
+            break;
+        }
+
+        case UNPACK_SEQUENCE: {
+            STACK_SHRINK(1);
+            STACK_GROW(oparg);
+            break;
+        }
+
+        case UNPACK_SEQUENCE_TWO_TUPLE: {
+            STACK_SHRINK(1);
+            STACK_GROW(oparg);
+            break;
+        }
+
+        case UNPACK_SEQUENCE_TUPLE: {
+            STACK_SHRINK(1);
+            STACK_GROW(oparg);
+            break;
+        }
+
+        case UNPACK_SEQUENCE_LIST: {
+            STACK_SHRINK(1);
+            STACK_GROW(oparg);
+            break;
+        }
+
+        case UNPACK_EX: {
+            STACK_GROW((oparg & 0xFF) + (oparg >> 8));
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1 - (oparg >> 8))), true);
+            break;
+        }
+
+        case STORE_ATTR: {
+            STACK_SHRINK(2);
+            break;
+        }
+
+        case DELETE_ATTR: {
+            STACK_SHRINK(1);
+            break;
+        }
+
+        case STORE_GLOBAL: {
+            STACK_SHRINK(1);
+            break;
+        }
+
+        case DELETE_GLOBAL: {
+            break;
+        }
+
+        case _LOAD_LOCALS: {
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case _LOAD_FROM_DICT_OR_GLOBALS: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case LOAD_GLOBAL: {
+            STACK_GROW(1);
+            STACK_GROW(((oparg & 1) ? 1 : 0));
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1 - (oparg & 1 ? 1 : 0))), true);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-(oparg & 1 ? 1 : 0))), true);
+            break;
+        }
+
+        case _GUARD_GLOBALS_VERSION: {
+            break;
+        }
+
+        case _GUARD_BUILTINS_VERSION: {
+            break;
+        }
+
+        case _LOAD_GLOBAL_MODULE: {
+            STACK_GROW(1);
+            STACK_GROW(((oparg & 1) ? 1 : 0));
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1 - (oparg & 1 ? 1 : 0))), true);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-(oparg & 1 ? 1 : 0))), true);
+            break;
+        }
+
+        case _LOAD_GLOBAL_BUILTINS: {
+            STACK_GROW(1);
+            STACK_GROW(((oparg & 1) ? 1 : 0));
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1 - (oparg & 1 ? 1 : 0))), true);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-(oparg & 1 ? 1 : 0))), true);
+            break;
+        }
+
+        case DELETE_FAST: {
+            break;
+        }
+
+        case DELETE_DEREF: {
+            break;
+        }
+
+        case LOAD_FROM_DICT_OR_DEREF: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case LOAD_DEREF: {
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case STORE_DEREF: {
+            STACK_SHRINK(1);
+            break;
+        }
+
+        case COPY_FREE_VARS: {
+            break;
+        }
+
+        case BUILD_STRING: {
+            STACK_SHRINK(oparg);
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case BUILD_TUPLE: {
+            STACK_SHRINK(oparg);
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case BUILD_LIST: {
+            STACK_SHRINK(oparg);
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case LIST_EXTEND: {
+            STACK_SHRINK(1);
+            break;
+        }
+
+        case SET_UPDATE: {
+            STACK_SHRINK(1);
+            break;
+        }
+
+        case BUILD_SET: {
+            STACK_SHRINK(oparg);
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case BUILD_MAP: {
+            STACK_SHRINK(oparg*2);
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case SETUP_ANNOTATIONS: {
+            break;
+        }
+
+        case BUILD_CONST_KEY_MAP: {
+            STACK_SHRINK(oparg);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case DICT_UPDATE: {
+            STACK_SHRINK(1);
+            break;
+        }
+
+        case DICT_MERGE: {
+            STACK_SHRINK(1);
+            break;
+        }
+
+        case MAP_ADD: {
+            STACK_SHRINK(2);
+            break;
+        }
+
+        case LOAD_SUPER_ATTR_ATTR: {
+            STACK_SHRINK(2);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(0)), true);
+            break;
+        }
+
+        case LOAD_SUPER_ATTR_METHOD: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-2)), true);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case LOAD_ATTR: {
+            STACK_GROW(((oparg & 1) ? 1 : 0));
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1 - (oparg & 1 ? 1 : 0))), true);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-(oparg & 1 ? 1 : 0))), true);
+            break;
+        }
+
+        case _GUARD_TYPE_VERSION: {
+            break;
+        }
+
+        case _CHECK_MANAGED_OBJECT_HAS_VALUES: {
+            break;
+        }
+
+        case _LOAD_ATTR_INSTANCE_VALUE: {
+            STACK_GROW(((oparg & 1) ? 1 : 0));
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1 - (oparg & 1 ? 1 : 0))), true);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-(oparg & 1 ? 1 : 0))), true);
+            break;
+        }
+
+        case COMPARE_OP: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case COMPARE_OP_FLOAT: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case COMPARE_OP_INT: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case COMPARE_OP_STR: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case IS_OP: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case CONTAINS_OP: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case CHECK_EG_MATCH: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-2)), true);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case CHECK_EXC_MATCH: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case IS_NONE: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case GET_LEN: {
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case MATCH_CLASS: {
+            STACK_SHRINK(2);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case MATCH_MAPPING: {
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case MATCH_SEQUENCE: {
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case MATCH_KEYS: {
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case GET_ITER: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case GET_YIELD_FROM_ITER: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case _ITER_CHECK_LIST: {
+            break;
+        }
+
+        case _IS_ITER_EXHAUSTED_LIST: {
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case _ITER_NEXT_LIST: {
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case _ITER_CHECK_TUPLE: {
+            break;
+        }
+
+        case _IS_ITER_EXHAUSTED_TUPLE: {
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case _ITER_NEXT_TUPLE: {
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case _ITER_CHECK_RANGE: {
+            break;
+        }
+
+        case _IS_ITER_EXHAUSTED_RANGE: {
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case _ITER_NEXT_RANGE: {
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case WITH_EXCEPT_START: {
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case PUSH_EXC_INFO: {
+            STACK_GROW(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-2)), true);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case CALL_NO_KW_TYPE_1: {
+            STACK_SHRINK(oparg);
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case CALL_NO_KW_STR_1: {
+            STACK_SHRINK(oparg);
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case CALL_NO_KW_TUPLE_1: {
+            STACK_SHRINK(oparg);
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case EXIT_INIT_CHECK: {
+            STACK_SHRINK(1);
+            break;
+        }
+
+        case CALL_NO_KW_BUILTIN_O: {
+            STACK_SHRINK(oparg);
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case CALL_NO_KW_BUILTIN_FAST: {
+            STACK_SHRINK(oparg);
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case CALL_NO_KW_LEN: {
+            STACK_SHRINK(oparg);
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case CALL_NO_KW_ISINSTANCE: {
+            STACK_SHRINK(oparg);
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case CALL_NO_KW_METHOD_DESCRIPTOR_O: {
+            STACK_SHRINK(oparg);
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS: {
+            STACK_SHRINK(oparg);
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case CALL_NO_KW_METHOD_DESCRIPTOR_FAST: {
+            STACK_SHRINK(oparg);
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case MAKE_FUNCTION: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case SET_FUNCTION_ATTRIBUTE: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case BUILD_SLICE: {
+            STACK_SHRINK(((oparg == 3) ? 1 : 0));
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case CONVERT_VALUE: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case FORMAT_SIMPLE: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case FORMAT_WITH_SPEC: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case BINARY_OP: {
+            STACK_SHRINK(1);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case SWAP: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-2 - (oparg-2))), true);
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+            break;
+        }
+
+        case _POP_JUMP_IF_FALSE: {
+            STACK_SHRINK(1);
+            break;
+        }
+
+        case _POP_JUMP_IF_TRUE: {
+            STACK_SHRINK(1);
+            break;
+        }
+
+        case JUMP_TO_TOP: {
+            break;
+        }
+
+        case SAVE_IP: {
+            break;
+        }
+
+        case EXIT_TRACE: {
+            break;
+        }
+
+        case INSERT: {
+            PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1 - oparg)), true);
+            break;
+        }
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 5efa36fcf5c62..e9a5cf59e7d68 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -3743,6 +3743,11 @@ dummy_func(
             return frame;
         }
 
+        op(INSERT, (unused[oparg], top -- top, unused[oparg])) {
+            // Inserts TOS at position specified by oparg;
+            memmove(&stack_pointer[-1 - oparg], &stack_pointer[-oparg], oparg * sizeof(stack_pointer[0]));
+        }
+
 
 // END BYTECODES //
 
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index 5e3c84b2b4b61..85d27777423ab 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -2733,3 +2733,12 @@
             return frame;
             break;
         }
+
+        case INSERT: {
+            PyObject *top;
+            top = stack_pointer[-1];
+            // Inserts TOS at position specified by oparg;
+            memmove(&stack_pointer[-1 - oparg], &stack_pointer[-oparg], oparg * sizeof(stack_pointer[0]));
+            stack_pointer[-1 - oparg] = top;
+            break;
+        }
diff --git a/Python/optimizer.c b/Python/optimizer.c
index 6c730aa14b9a4..d3ac2424038ef 100644
--- a/Python/optimizer.c
+++ b/Python/optimizer.c
@@ -4,6 +4,7 @@
 #include "pycore_opcode.h"
 #include "pycore_opcode_metadata.h"
 #include "pycore_opcode_utils.h"
+#include "pycore_optimizer.h"
 #include "pycore_pystate.h"       // _PyInterpreterState_GET()
 #include "pycore_uops.h"
 #include "cpython/optimizer.h"
@@ -103,7 +104,8 @@ error_optimize(
     _PyOptimizerObject* self,
     PyCodeObject *code,
     _Py_CODEUNIT *instr,
-    _PyExecutorObject **exec)
+    _PyExecutorObject **exec,
+    int Py_UNUSED(stack_entries))
 {
     PyErr_Format(PyExc_SystemError, "Should never call error_optimize");
     return -1;
@@ -164,7 +166,7 @@ _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNI
     }
     _PyOptimizerObject *opt = interp->optimizer;
     _PyExecutorObject *executor = NULL;
-    int err = opt->optimize(opt, code, dest, &executor);
+    int err = opt->optimize(opt, code, dest, &executor, (int)(stack_pointer - _PyFrame_Stackbase(frame)));
     if (err <= 0) {
         assert(executor == NULL);
         if (err < 0) {
@@ -254,7 +256,9 @@ counter_optimize(
     _PyOptimizerObject* self,
     PyCodeObject *code,
     _Py_CODEUNIT *instr,
-    _PyExecutorObject **exec_ptr)
+    _PyExecutorObject **exec_ptr,
+    int Py_UNUSED(curr_stackentries)
+)
 {
     _PyCounterExecutorObject *executor = (_PyCounterExecutorObject *)_PyObject_New(&CounterExecutor_Type);
     if (executor == NULL) {
@@ -684,7 +688,8 @@ uop_optimize(
     _PyOptimizerObject *self,
     PyCodeObject *code,
     _Py_CODEUNIT *instr,
-    _PyExecutorObject **exec_ptr)
+    _PyExecutorObject **exec_ptr,
+    int curr_stackentries)
 {
     _PyUOpInstruction trace[_Py_UOP_MAX_TRACE_LENGTH];
     int trace_length = translate_bytecode_to_trace(code, instr, trace, _Py_UOP_MAX_TRACE_LENGTH);
@@ -693,6 +698,10 @@ uop_optimize(
         return trace_length;
     }
     OBJECT_STAT_INC(optimization_traces_created);
+    char *uop_optimize = Py_GETENV("PYTHONUOPSOPTIMIZE");
+    if (uop_optimize != NULL && *uop_optimize > '0') {
+        trace_length = _Py_uop_analyze_and_optimize(code, trace, trace_length, curr_stackentries);
+    }
     _PyUOpExecutorObject *executor = PyObject_NewVar(_PyUOpExecutorObject, &UOpExecutor_Type, trace_length);
     if (executor == NULL) {
         return -1;
diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c
new file mode 100644
index 0000000000000..e48e018052c71
--- /dev/null
+++ b/Python/optimizer_analysis.c
@@ -0,0 +1,26 @@
+#include "Python.h"
+#include "opcode.h"
+#include "pycore_interp.h"
+#include "pycore_opcode.h"
+#include "pycore_opcode_metadata.h"
+#include "pycore_opcode_utils.h"
+#include "pycore_pystate.h"       // _PyInterpreterState_GET()
+#include "pycore_uops.h"
+#include "pycore_long.h"
+#include "cpython/optimizer.h"
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+#include "pycore_optimizer.h"
+
+
+int
+_Py_uop_analyze_and_optimize(
+    PyCodeObject *co,
+    _PyUOpInstruction *trace,
+    int trace_len,
+    int curr_stacklen
+)
+{
+    return trace_len;
+}
diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py
index 9bc7285e18b2f..90334d0e79da8 100644
--- a/Tools/c-analyzer/cpython/_parser.py
+++ b/Tools/c-analyzer/cpython/_parser.py
@@ -84,6 +84,7 @@ def clean_lines(text):
 Python/frozen_modules/*.h
 Python/generated_cases.c.h
 Python/executor_cases.c.h
+Python/abstract_interp_cases.c.h
 
 # not actually source
 Python/bytecodes.c
diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv
index c64d391bae13b..d1ac0410619c9 100644
--- a/Tools/c-analyzer/cpython/ignored.tsv
+++ b/Tools/c-analyzer/cpython/ignored.tsv
@@ -716,3 +716,5 @@ Modules/expat/xmlrole.c	-	error	-
 ## other
 Modules/_io/_iomodule.c	-	_PyIO_Module	-
 Modules/_sqlite/module.c	-	_sqlite3module	-
+Python/optimizer_analysis.c	-	_Py_PartitionRootNode_Type	-
+Python/optimizer_analysis.c	-	_Py_UOpsAbstractInterpContext_Type	-
diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py
index e78b0edff9a0c..e170e110f80cf 100644
--- a/Tools/cases_generator/generate_cases.py
+++ b/Tools/cases_generator/generate_cases.py
@@ -16,6 +16,7 @@
 from flags import InstructionFlags, variable_used
 from instructions import (
     AnyInstruction,
+    AbstractInstruction,
     Component,
     Instruction,
     MacroInstruction,
@@ -44,6 +45,9 @@
 DEFAULT_EXECUTOR_OUTPUT = os.path.relpath(
     os.path.join(ROOT, "Python/executor_cases.c.h")
 )
+DEFAULT_ABSTRACT_INTERPRETER_OUTPUT = os.path.relpath(
+    os.path.join(ROOT, "Python/abstract_interp_cases.c.h")
+)
 
 # Constants used instead of size for macro expansions.
 # Note: 1, 2, 4 must match actual cache entry sizes.
@@ -58,6 +62,23 @@
 
 INSTR_FMT_PREFIX = "INSTR_FMT_"
 
+# TODO: generate all these after updating the DSL
+SPECIALLY_HANDLED_ABSTRACT_INSTR = {
+    "LOAD_FAST",
+    "LOAD_FAST_CHECK",
+    "LOAD_FAST_AND_CLEAR",
+    "LOAD_CONST",
+    "STORE_FAST",
+    "STORE_FAST_MAYBE_NULL",
+    "COPY",
+
+    # Arithmetic
+    "_BINARY_OP_MULTIPLY_INT",
+    "_BINARY_OP_ADD_INT",
+    "_BINARY_OP_SUBTRACT_INT",
+
+}
+
 arg_parser = argparse.ArgumentParser(
     description="Generate the code for the interpreter switch.",
     formatter_class=argparse.ArgumentDefaultsHelpFormatter,
@@ -92,7 +113,13 @@
     help="Write executor cases to this file",
     default=DEFAULT_EXECUTOR_OUTPUT,
 )
-
+arg_parser.add_argument(
+    "-a",
+    "--abstract-interpreter-cases",
+    type=str,
+    help="Write abstract interpreter cases to this file",
+    default=DEFAULT_ABSTRACT_INTERPRETER_OUTPUT,
+)
 
 class Generator(Analyzer):
     def get_stack_effect_info(
@@ -109,7 +136,7 @@ def effect_str(effects: list[StackEffect]) -> str:
         pushed: str | None
         match thing:
             case parsing.InstDef():
-                if thing.kind != "op":
+                if thing.kind != "op" or self.instrs[thing.name].is_viable_uop():
                     instr = self.instrs[thing.name]
                     popped = effect_str(instr.input_effects)
                     pushed = effect_str(instr.output_effects)
@@ -588,6 +615,35 @@ def write_executor_instructions(
             file=sys.stderr,
         )
 
+    def write_abstract_interpreter_instructions(
+        self, abstract_interpreter_filename: str, emit_line_directives: bool
+    ) -> None:
+        """Generate cases for the Tier 2 abstract interpreter/analzyer."""
+        with open(abstract_interpreter_filename, "w") as f:
+            self.out = Formatter(f, 8, emit_line_directives)
+            self.write_provenance_header()
+            for thing in self.everything:
+                match thing:
+                    case OverriddenInstructionPlaceHolder():
+                        pass
+                    case parsing.InstDef():
+                        instr = AbstractInstruction(self.instrs[thing.name].inst)
+                        if instr.is_viable_uop() and instr.name not in SPECIALLY_HANDLED_ABSTRACT_INSTR:
+                            self.out.emit("")
+                            with self.out.block(f"case {thing.name}:"):
+                                instr.write(self.out, tier=TIER_TWO)
+                                self.out.emit("break;")
+                    case parsing.Macro():
+                        pass
+                    case parsing.Pseudo():
+                        pass
+                    case _:
+                        typing.assert_never(thing)
+        print(
+            f"Wrote some stuff to {abstract_interpreter_filename}",
+            file=sys.stderr,
+        )
+
     def write_overridden_instr_place_holder(
         self, place_holder: OverriddenInstructionPlaceHolder
     ) -> None:
@@ -629,6 +685,8 @@ def main():
     a.write_instructions(args.output, args.emit_line_directives)
     a.write_metadata(args.metadata, args.pymetadata)
     a.write_executor_instructions(args.executor_cases, args.emit_line_directives)
+    a.write_abstract_interpreter_instructions(args.abstract_interpreter_cases,
+                                              args.emit_line_directives)
 
 
 if __name__ == "__main__":
diff --git a/Tools/cases_generator/instructions.py b/Tools/cases_generator/instructions.py
index aa94dbb07ea1c..a505df08fa265 100644
--- a/Tools/cases_generator/instructions.py
+++ b/Tools/cases_generator/instructions.py
@@ -248,6 +248,25 @@ def write_body(
 InstructionOrCacheEffect = Instruction | parsing.CacheEffect
 
 
+# Instruction used for abstract interpretation.
+class AbstractInstruction(Instruction):
+    def __init__(self, inst: parsing.InstDef):
+        super().__init__(inst)
+
+    def write(self, out: Formatter, tier: Tiers = TIER_ONE) -> None:
+        """Write one abstract instruction, sans prologue and epilogue."""
+        stacking.write_single_instr_for_abstract_interp(self, out)
+
+    def write_body(
+        self,
+        out: Formatter,
+        dedent: int,
+        active_caches: list[ActiveCacheEffect],
+        tier: Tiers = TIER_ONE,
+    ) -> None:
+        pass
+
+
 @dataclasses.dataclass
 class Component:
     instr: Instruction
diff --git a/Tools/cases_generator/stacking.py b/Tools/cases_generator/stacking.py
index 9bb7f46844224..31a21e026cb49 100644
--- a/Tools/cases_generator/stacking.py
+++ b/Tools/cases_generator/stacking.py
@@ -391,3 +391,32 @@ def write_components(
                     poke.as_stack_effect(),
                     poke.effect,
                 )
+
+
+def write_single_instr_for_abstract_interp(
+    instr: Instruction, out: Formatter
+):
+    try:
+        _write_components_for_abstract_interp(
+            [Component(instr, instr.active_caches)],
+            out,
+        )
+    except AssertionError as err:
+        raise AssertionError(f"Error writing abstract instruction {instr.name}") from err
+
+
+def _write_components_for_abstract_interp(
+    parts: list[Component],
+    out: Formatter,
+):
+    managers = get_managers(parts)
+    for mgr in managers:
+        if mgr is managers[-1]:
+            out.stack_adjust(mgr.final_offset.deep, mgr.final_offset.high)
+            # Use clone() since adjust_inverse() mutates final_offset
+            mgr.adjust_inverse(mgr.final_offset.clone())
+        # NULL out the output stack effects
+        for poke in mgr.pokes:
+            if not poke.effect.size and poke.effect.name not in mgr.instr.unmoved_names:
+                out.emit(f"PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)"
+                         f"PARTITIONNODE_NULLROOT, PEEK(-({poke.offset.as_index()})), true);")



More information about the Python-checkins mailing list