https://github.com/python/cpython/commit/7c9ad27dd1fc9e05149b471b055f18ad64cd05f3
commit: 7c9ad27dd1fc9e05149b471b055f18ad64cd05f3
branch: main
author: Neko Asakura <[email protected]>
committer: markshannon <[email protected]>
date: 2026-05-02T19:59:51+01:00
summary:

gh-148871: extend and improve `LOAD_COMMON_CONSTANT` (GH-148971)

files:
M Include/internal/pycore_opcode_utils.h
M Lib/dis.py
M Lib/opcode.py
M Lib/test/test_ast/test_ast.py
M Lib/test/test_capi/test_opt.py
M Lib/test/test_code.py
M Lib/test/test_compile.py
M Lib/test/test_dis.py
M Lib/test/test_peepholer.py
M Objects/codeobject.c
M Programs/test_frozenmain.h
M Python/flowgraph.c
M Python/optimizer_bytecodes.c
M Python/optimizer_cases.c.h
M Python/pylifecycle.c

diff --git a/Include/internal/pycore_opcode_utils.h 
b/Include/internal/pycore_opcode_utils.h
index 1e71784c809d2d..3e2c4ae411c925 100644
--- a/Include/internal/pycore_opcode_utils.h
+++ b/Include/internal/pycore_opcode_utils.h
@@ -75,7 +75,12 @@ extern "C" {
 #define CONSTANT_BUILTIN_ANY 4
 #define CONSTANT_BUILTIN_LIST 5
 #define CONSTANT_BUILTIN_SET 6
-#define NUM_COMMON_CONSTANTS 7
+#define CONSTANT_NONE 7
+#define CONSTANT_EMPTY_STR 8
+#define CONSTANT_TRUE 9
+#define CONSTANT_FALSE 10
+#define CONSTANT_MINUS_ONE 11
+#define NUM_COMMON_CONSTANTS 12
 
 /* Values used in the oparg for RESUME */
 #define RESUME_AT_FUNC_START 0
diff --git a/Lib/dis.py b/Lib/dis.py
index 58c7f6419032c6..64f3450da3071b 100644
--- a/Lib/dis.py
+++ b/Lib/dis.py
@@ -643,6 +643,7 @@ def get_argval_argrepr(self, op, arg, offset):
                 argrepr = _intrinsic_2_descs[arg]
             elif deop == LOAD_COMMON_CONSTANT:
                 obj = _common_constants[arg]
+                argval = obj
                 if isinstance(obj, type):
                     argrepr = obj.__name__
                 else:
@@ -692,10 +693,15 @@ def _get_const_value(op, arg, co_consts):
        Otherwise (if it is a LOAD_CONST and co_consts is not
        provided) returns the dis.UNKNOWN sentinel.
     """
-    assert op in hasconst or op == LOAD_SMALL_INT
+    assert op in hasconst or op == LOAD_SMALL_INT or op == LOAD_COMMON_CONSTANT
 
     if op == LOAD_SMALL_INT:
         return arg
+    if op == LOAD_COMMON_CONSTANT:
+        # Opargs 0-6 are callables; 7-11 are literal values.
+        if 7 <= arg <= 11:
+            return _common_constants[arg]
+        return UNKNOWN
     argval = UNKNOWN
     if co_consts is not None:
         argval = co_consts[arg]
@@ -1015,8 +1021,9 @@ def _find_imports(co):
         if op == IMPORT_NAME and i >= 2:
             from_op = opargs[i-1]
             level_op = opargs[i-2]
-            if (from_op[0] in hasconst and
-                (level_op[0] in hasconst or level_op[0] == LOAD_SMALL_INT)):
+            if ((from_op[0] in hasconst or from_op[0] == LOAD_COMMON_CONSTANT) 
and
+                (level_op[0] in hasconst or level_op[0] == LOAD_SMALL_INT or
+                 level_op[0] == LOAD_COMMON_CONSTANT)):
                 level = _get_const_value(level_op[0], level_op[1], consts)
                 fromlist = _get_const_value(from_op[0], from_op[1], consts)
                 # IMPORT_NAME encodes lazy/eager flags in bits 0-1,
diff --git a/Lib/opcode.py b/Lib/opcode.py
index 8466814d2257c3..4e60fb5af34f22 100644
--- a/Lib/opcode.py
+++ b/Lib/opcode.py
@@ -41,7 +41,10 @@
 _special_method_names = _opcode.get_special_method_names()
 _common_constants = [builtins.AssertionError, builtins.NotImplementedError,
                      builtins.tuple, builtins.all, builtins.any, builtins.list,
-                     builtins.set]
+                     builtins.set,
+                     # Append-only — must match CONSTANT_* in
+                     # Include/internal/pycore_opcode_utils.h.
+                     None, "", True, False, -1]
 _nb_ops = _opcode.get_nb_ops()
 
 hascompare = [opmap["COMPARE_OP"]]
diff --git a/Lib/test/test_ast/test_ast.py b/Lib/test/test_ast/test_ast.py
index fcc6c93eb86981..af8b334da03e70 100644
--- a/Lib/test/test_ast/test_ast.py
+++ b/Lib/test/test_ast/test_ast.py
@@ -2685,11 +2685,12 @@ def test_get_docstring(self):
 
     def get_load_const(self, tree):
         # Compile to bytecode, disassemble and get parameter of LOAD_CONST
-        # instructions
+        # and LOAD_COMMON_CONSTANT instructions
         co = compile(tree, '<string>', 'exec')
         consts = []
         for instr in dis.get_instructions(co):
-            if instr.opcode in dis.hasconst:
+            if instr.opcode in dis.hasconst or \
+                    instr.opname == 'LOAD_COMMON_CONSTANT':
                 consts.append(instr.argval)
         return consts
 
diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py
index 7118dfeed9faee..d4af910fb68c61 100644
--- a/Lib/test/test_capi/test_opt.py
+++ b/Lib/test/test_capi/test_opt.py
@@ -3446,6 +3446,27 @@ def testfunc(n):
         self.assertIn("_BUILD_LIST", uops)
         self.assertNotIn("_LOAD_COMMON_CONSTANT", uops)
 
+    def test_load_common_constant_new_literals(self):
+        def testfunc(n):
+            x = None
+            s = ""
+            t = True
+            f = False
+            m = -1
+            for _ in range(n):
+                x = None
+                s = ""
+                t = True
+                f = False
+                m = -1
+            return x, s, t, f, m
+        res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
+        self.assertEqual(res, (None, "", True, False, -1))
+        self.assertIsNotNone(ex)
+        uops = get_opnames(ex)
+        self.assertNotIn("_LOAD_COMMON_CONSTANT", uops)
+        self.assertIn("_LOAD_CONST_INLINE_BORROW", uops)
+
     def test_load_small_int(self):
         def testfunc(n):
             x = 0
diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py
index 5e802a929b14b8..3588872ed23ac4 100644
--- a/Lib/test/test_code.py
+++ b/Lib/test/test_code.py
@@ -87,7 +87,7 @@
 freevars: ()
 nlocals: 0
 flags: 67108867
-consts: ("'doc string'", 'None')
+consts: ("'doc string'",)
 
 >>> def keywordonly_args(a,b,*,k1):
 ...     return a,b,k1
@@ -161,7 +161,7 @@
 freevars: ()
 nlocals: 3
 flags: 67108995
-consts: ("'This is a docstring from async function'", 'None')
+consts: ("'This is a docstring from async function'",)
 
 >>> def no_docstring(x, y, z):
 ...     return x + "hello" + y + z + "world"
@@ -532,7 +532,7 @@ def test_co_positions_artificial_instructions(self):
             ],
             [
                 ("PUSH_EXC_INFO", None),
-                ("LOAD_CONST", None), # artificial 'None'
+                ("LOAD_COMMON_CONSTANT", None), # artificial 'None'
                 ("STORE_NAME", "e"),  # XX: we know the location for this
                 ("DELETE_NAME", "e"),
                 ("RERAISE", 1),
diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py
index ac8837359c1445..9edbca3c383b43 100644
--- a/Lib/test/test_compile.py
+++ b/Lib/test/test_compile.py
@@ -2485,12 +2485,13 @@ def f():
             start_line, end_line, _, _ = instr.positions
             self.assertEqual(start_line, end_line)
 
-        # Expect four `LOAD_CONST None` instructions:
+        # Expect four `None`-loading instructions:
         # three for the no-exception __exit__ call, and one for the return.
         # They should all have the locations of the context manager ('xyz').
 
         load_none = [instr for instr in dis.get_instructions(f) if
-                     instr.opname == 'LOAD_CONST' and instr.argval is None]
+                     instr.opname in ('LOAD_CONST', 'LOAD_COMMON_CONSTANT')
+                     and instr.argval is None]
         return_value = [instr for instr in dis.get_instructions(f) if
                         instr.opname == 'RETURN_VALUE']
 
diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py
index cc9bc918b616e2..8be104585814f4 100644
--- a/Lib/test/test_dis.py
+++ b/Lib/test/test_dis.py
@@ -56,7 +56,7 @@ def cm(cls, x):
               COMPARE_OP              72 (==)
               LOAD_FAST_BORROW         0 (self)
               STORE_ATTR               0 (x)
-              LOAD_CONST               1 (None)
+              LOAD_COMMON_CONSTANT     7 (None)
               RETURN_VALUE
 """ % (_C.__init__.__code__.co_firstlineno, 
_C.__init__.__code__.co_firstlineno + 1,)
 
@@ -67,7 +67,7 @@ def cm(cls, x):
           COMPARE_OP              72 (==)
           LOAD_FAST_BORROW         0
           STORE_ATTR               0
-          LOAD_CONST               1
+          LOAD_COMMON_CONSTANT     7 (None)
           RETURN_VALUE
 """
 
@@ -79,7 +79,7 @@ def cm(cls, x):
               COMPARE_OP              72 (==)
               LOAD_FAST_BORROW         0 (cls)
               STORE_ATTR               0 (x)
-              LOAD_CONST               1 (None)
+              LOAD_COMMON_CONSTANT     7 (None)
               RETURN_VALUE
 """ % (_C.cm.__code__.co_firstlineno, _C.cm.__code__.co_firstlineno + 2,)
 
@@ -90,7 +90,7 @@ def cm(cls, x):
               LOAD_SMALL_INT           1
               COMPARE_OP              72 (==)
               STORE_FAST               0 (x)
-              LOAD_CONST               1 (None)
+              LOAD_COMMON_CONSTANT     7 (None)
               RETURN_VALUE
 """ % (_C.sm.__code__.co_firstlineno, _C.sm.__code__.co_firstlineno + 2,)
 
@@ -182,7 +182,7 @@ def bug708901():
 
 %3d   L2:     END_FOR
               POP_ITER
-              LOAD_CONST               1 (None)
+              LOAD_COMMON_CONSTANT     7 (None)
               RETURN_VALUE
 """ % (bug708901.__code__.co_firstlineno,
        bug708901.__code__.co_firstlineno + 1,
@@ -229,7 +229,7 @@ def bug42562():
 
 dis_bug42562 = """\
           RESUME                   0
-          LOAD_CONST               0 (None)
+          LOAD_COMMON_CONSTANT     7 (None)
           RETURN_VALUE
 """
 
@@ -282,7 +282,7 @@ def wrap_func_w_kwargs():
               LOAD_CONST               1 (('c',))
               CALL_KW                  3
               POP_TOP
-              LOAD_CONST               2 (None)
+              LOAD_COMMON_CONSTANT     7 (None)
               RETURN_VALUE
 """ % (wrap_func_w_kwargs.__code__.co_firstlineno,
        wrap_func_w_kwargs.__code__.co_firstlineno + 1)
@@ -295,7 +295,7 @@ def wrap_func_w_kwargs():
               IMPORT_NAME              2 (math + eager)
               CALL_INTRINSIC_1         2 (INTRINSIC_IMPORT_STAR)
               POP_TOP
-              LOAD_CONST               2 (None)
+              LOAD_COMMON_CONSTANT     7 (None)
               RETURN_VALUE
 """
 
@@ -322,7 +322,7 @@ def wrap_func_w_kwargs():
 
 %3d           LOAD_GLOBAL              0 (spam)
               POP_TOP
-              LOAD_CONST               0 (None)
+              LOAD_COMMON_CONSTANT     7 (None)
               RETURN_VALUE
 """
 
@@ -331,19 +331,19 @@ def wrap_func_w_kwargs():
 
 %4d           LOAD_GLOBAL              0 (spam)
                POP_TOP
-               LOAD_CONST               0 (None)
+               LOAD_COMMON_CONSTANT     7 (None)
                RETURN_VALUE
 """
 
 dis_module_expected_results = """\
 Disassembly of f:
   4           RESUME                   0
-              LOAD_CONST               0 (None)
+              LOAD_COMMON_CONSTANT     7 (None)
               RETURN_VALUE
 
 Disassembly of g:
   5           RESUME                   0
-              LOAD_CONST               0 (None)
+              LOAD_COMMON_CONSTANT     7 (None)
               RETURN_VALUE
 
 """
@@ -368,7 +368,7 @@ def wrap_func_w_kwargs():
               LOAD_SMALL_INT           1
               BINARY_OP                0 (+)
               STORE_NAME               0 (x)
-              LOAD_CONST               1 (None)
+              LOAD_COMMON_CONSTANT     7 (None)
               RETURN_VALUE
 """
 
@@ -409,7 +409,7 @@ def wrap_func_w_kwargs():
                LOAD_SMALL_INT           0
                CALL                     1
                STORE_SUBSCR
-               LOAD_CONST               2 (None)
+               LOAD_COMMON_CONSTANT     7 (None)
                RETURN_VALUE
 """
 
@@ -427,7 +427,7 @@ def foo(a: int, b: str) -> str:
               MAKE_FUNCTION
               SET_FUNCTION_ATTRIBUTE  16 (annotate)
               STORE_NAME               0 (foo)
-              LOAD_CONST               2 (None)
+              LOAD_COMMON_CONSTANT     7 (None)
               RETURN_VALUE
 """
 
@@ -477,14 +477,14 @@ def foo(a: int, b: str) -> str:
                 LOAD_ATTR                2 (__traceback__)
                 STORE_FAST               1 (tb)
         L7:     POP_EXCEPT
-                LOAD_CONST               1 (None)
+                LOAD_COMMON_CONSTANT     7 (None)
                 STORE_FAST               0 (e)
                 DELETE_FAST              0 (e)
 
 %4d            LOAD_FAST                1 (tb)
                 RETURN_VALUE
 
-  --    L8:     LOAD_CONST               1 (None)
+  --    L8:     LOAD_COMMON_CONSTANT     7 (None)
                 STORE_FAST               0 (e)
                 DELETE_FAST              0 (e)
                 RERAISE                  1
@@ -554,15 +554,15 @@ def _with(c):
 %4d           LOAD_SMALL_INT           1
                STORE_FAST               1 (x)
 
-%4d   L2:     LOAD_CONST               1 (None)
-               LOAD_CONST               1 (None)
-               LOAD_CONST               1 (None)
+%4d   L2:     LOAD_COMMON_CONSTANT     7 (None)
+               LOAD_COMMON_CONSTANT     7 (None)
+               LOAD_COMMON_CONSTANT     7 (None)
                CALL                     3
                POP_TOP
 
 %4d           LOAD_SMALL_INT           2
                STORE_FAST               2 (y)
-               LOAD_CONST               1 (None)
+               LOAD_COMMON_CONSTANT     7 (None)
                RETURN_VALUE
 
 %4d   L3:     PUSH_EXC_INFO
@@ -579,7 +579,7 @@ def _with(c):
 
 %4d           LOAD_SMALL_INT           2
                STORE_FAST               2 (y)
-               LOAD_CONST               1 (None)
+               LOAD_COMMON_CONSTANT     7 (None)
                RETURN_VALUE
 
   --   L8:     COPY                     3
@@ -617,7 +617,7 @@ async def _asyncwith(c):
                 CALL                     0
                 GET_AWAITABLE            1
                 PUSH_NULL
-                LOAD_CONST               0 (None)
+                LOAD_COMMON_CONSTANT     7 (None)
         L2:     SEND                     4 (to L5)
         L3:     YIELD_VALUE              1
         L4:     RESUME                   3
@@ -628,13 +628,13 @@ async def _asyncwith(c):
 %4d            LOAD_SMALL_INT           1
                 STORE_FAST               1 (x)
 
-%4d    L7:     LOAD_CONST               0 (None)
-                LOAD_CONST               0 (None)
-                LOAD_CONST               0 (None)
+%4d    L7:     LOAD_COMMON_CONSTANT     7 (None)
+                LOAD_COMMON_CONSTANT     7 (None)
+                LOAD_COMMON_CONSTANT     7 (None)
                 CALL                     3
                 GET_AWAITABLE            2
                 PUSH_NULL
-                LOAD_CONST               0 (None)
+                LOAD_COMMON_CONSTANT     7 (None)
         L8:     SEND                     4 (to L11)
         L9:     YIELD_VALUE              1
        L10:     RESUME                   3
@@ -644,7 +644,7 @@ async def _asyncwith(c):
 
 %4d            LOAD_SMALL_INT           2
                 STORE_FAST               2 (y)
-                LOAD_CONST               0 (None)
+                LOAD_COMMON_CONSTANT     7 (None)
                 RETURN_VALUE
 
 %4d   L12:     CLEANUP_THROW
@@ -655,7 +655,7 @@ async def _asyncwith(c):
                 WITH_EXCEPT_START
                 GET_AWAITABLE            2
                 PUSH_NULL
-                LOAD_CONST               0 (None)
+                LOAD_COMMON_CONSTANT     7 (None)
        L17:     SEND                     5 (to L21)
        L18:     YIELD_VALUE              1
        L19:     RESUME                   3
@@ -674,7 +674,7 @@ async def _asyncwith(c):
 
 %4d            LOAD_SMALL_INT           2
                 STORE_FAST               2 (y)
-                LOAD_CONST               0 (None)
+                LOAD_COMMON_CONSTANT     7 (None)
                 RETURN_VALUE
 
   --   L26:     COPY                     3
@@ -895,7 +895,7 @@ def foo(x):
                JUMP_BACKWARD           17 (to L2)
        L3:     END_FOR
                POP_ITER
-               LOAD_CONST               0 (None)
+               LOAD_COMMON_CONSTANT     7 (None)
                RETURN_VALUE
 
   --   L4:     CALL_INTRINSIC_1         3 (INTRINSIC_STOPITERATION_ERROR)
@@ -933,7 +933,7 @@ def loop_test():
 %3d           RESUME_CHECK{: <6}       0
 
 %3d           BUILD_LIST               0
-              LOAD_CONST               2 ((1, 2, 3))
+              LOAD_CONST               1 ((1, 2, 3))
               LIST_EXTEND              1
               LOAD_SMALL_INT           3
               BINARY_OP                5 (*)
@@ -949,7 +949,7 @@ def loop_test():
 
 %3d   L2:     END_FOR
               POP_ITER
-              LOAD_CONST               1 (None)
+              LOAD_COMMON_CONSTANT     7 (None)
               RETURN_VALUE
 """ % (loop_test.__code__.co_firstlineno,
        loop_test.__code__.co_firstlineno + 1,
@@ -967,7 +967,7 @@ def extended_arg_quick():
               UNPACK_EX              256
               POP_TOP
               STORE_FAST               0 (_)
-              LOAD_CONST               1 (None)
+              LOAD_COMMON_CONSTANT     7 (None)
               RETURN_VALUE
 """% (extended_arg_quick.__code__.co_firstlineno,
       extended_arg_quick.__code__.co_firstlineno + 1,)
@@ -1084,7 +1084,7 @@ def test_dis_with_some_positions(self):
             '',
             '2:3-3:15             NOP',
             '',
-            '3:11-3:15            LOAD_CONST               0 (None)',
+            '3:11-3:15            LOAD_COMMON_CONSTANT     7 (None)',
             '3:11-3:15            RETURN_VALUE',
             '',
             '  --         L1:     PUSH_EXC_INFO',
@@ -1115,7 +1115,7 @@ def test_dis_with_linenos_but_no_columns(self):
             '',
             '2:5-2:6            LOAD_SMALL_INT           1',
             '2:?-2:?            STORE_FAST               0 (x)',
-            '2:?-2:?            LOAD_CONST               1 (None)',
+            '2:?-2:?            LOAD_COMMON_CONSTANT     7 (None)',
             '2:?-2:?            RETURN_VALUE',
             '',
         ])
@@ -1128,7 +1128,7 @@ def f():
         f.__code__ = f.__code__.replace(co_linetable=b'')
         expect = '\n'.join([
             '          RESUME                   0',
-            '          LOAD_CONST               0 (None)',
+            '          LOAD_COMMON_CONSTANT     7 (None)',
             '          RETURN_VALUE',
             '',
         ])
@@ -1533,7 +1533,6 @@ def f(c=c):
 Flags:             OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR
 Constants:
    0: <code object f at (.*), file "(.*)", line (.*)>
-   1: None
 Variable names:
    0: a
    1: b
@@ -1605,7 +1604,6 @@ def f(c=c):
 Flags:             0x0
 Constants:
    0: 1
-   1: None
 Names:
    0: x"""
 
@@ -1640,7 +1638,6 @@ async def async_def():
 Flags:             OPTIMIZED, NEWLOCALS, COROUTINE
 Constants:
    0: 1
-   1: None
 Names:
    0: b
    1: c
@@ -1790,7 +1787,7 @@ def _prepare_test_cases():
   make_inst(opname='MAKE_CELL', arg=0, argval='a', argrepr='a', offset=0, 
start_offset=0, starts_line=True, line_number=None),
   make_inst(opname='MAKE_CELL', arg=1, argval='b', argrepr='b', offset=2, 
start_offset=2, starts_line=False, line_number=None),
   make_inst(opname='RESUME', arg=0, argval=0, argrepr='', offset=4, 
start_offset=4, starts_line=True, line_number=1, cache_info=[('counter', 1, 
b'\x00\x00')]),
-  make_inst(opname='LOAD_CONST', arg=4, argval=(3, 4), argrepr='(3, 4)', 
offset=8, start_offset=8, starts_line=True, line_number=2),
+  make_inst(opname='LOAD_CONST', arg=3, argval=(3, 4), argrepr='(3, 4)', 
offset=8, start_offset=8, starts_line=True, line_number=2),
   make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='a', argrepr='a', 
offset=10, start_offset=10, starts_line=False, line_number=2),
   make_inst(opname='LOAD_FAST_BORROW', arg=1, argval='b', argrepr='b', 
offset=12, start_offset=12, starts_line=False, line_number=2),
   make_inst(opname='BUILD_TUPLE', arg=2, argval=2, argrepr='', offset=14, 
start_offset=14, starts_line=False, line_number=2),
@@ -1802,11 +1799,11 @@ def _prepare_test_cases():
   make_inst(opname='LOAD_GLOBAL', arg=1, argval='print', argrepr='print + 
NULL', offset=26, start_offset=26, starts_line=True, line_number=7, 
cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), 
('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, 
b'\x00\x00')]),
   make_inst(opname='LOAD_DEREF', arg=0, argval='a', argrepr='a', offset=36, 
start_offset=36, starts_line=False, line_number=7),
   make_inst(opname='LOAD_DEREF', arg=1, argval='b', argrepr='b', offset=38, 
start_offset=38, starts_line=False, line_number=7),
-  make_inst(opname='LOAD_CONST', arg=2, argval='', argrepr="''", offset=40, 
start_offset=40, starts_line=False, line_number=7),
+  make_inst(opname='LOAD_COMMON_CONSTANT', arg=8, argval='', argrepr="''", 
offset=40, start_offset=40, starts_line=False, line_number=7),
   make_inst(opname='LOAD_SMALL_INT', arg=1, argval=1, argrepr='', offset=42, 
start_offset=42, starts_line=False, line_number=7),
   make_inst(opname='BUILD_LIST', arg=0, argval=0, argrepr='', offset=44, 
start_offset=44, starts_line=False, line_number=7),
   make_inst(opname='BUILD_MAP', arg=0, argval=0, argrepr='', offset=46, 
start_offset=46, starts_line=False, line_number=7),
-  make_inst(opname='LOAD_CONST', arg=3, argval='Hello world!', argrepr="'Hello 
world!'", offset=48, start_offset=48, starts_line=False, line_number=7),
+  make_inst(opname='LOAD_CONST', arg=2, argval='Hello world!', argrepr="'Hello 
world!'", offset=48, start_offset=48, starts_line=False, line_number=7),
   make_inst(opname='CALL', arg=7, argval=7, argrepr='', offset=50, 
start_offset=50, starts_line=False, line_number=7, cache_info=[('counter', 1, 
b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
   make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=58, 
start_offset=58, starts_line=False, line_number=7),
   make_inst(opname='LOAD_FAST_BORROW', arg=2, argval='f', argrepr='f', 
offset=60, start_offset=60, starts_line=True, line_number=8),
@@ -1851,7 +1848,7 @@ def _prepare_test_cases():
   make_inst(opname='LOAD_FAST_BORROW_LOAD_FAST_BORROW', arg=1, argval=('e', 
'f'), argrepr='e, f', offset=24, start_offset=24, starts_line=False, 
line_number=4),
   make_inst(opname='CALL', arg=6, argval=6, argrepr='', offset=26, 
start_offset=26, starts_line=False, line_number=4, cache_info=[('counter', 1, 
b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
   make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=34, 
start_offset=34, starts_line=False, line_number=4),
-  make_inst(opname='LOAD_CONST', arg=0, argval=None, argrepr='None', 
offset=36, start_offset=36, starts_line=False, line_number=4),
+  make_inst(opname='LOAD_COMMON_CONSTANT', arg=7, argval=None, argrepr='None', 
offset=36, start_offset=36, starts_line=False, line_number=4),
   make_inst(opname='RETURN_VALUE', arg=None, argval=None, argrepr='', 
offset=38, start_offset=38, starts_line=False, line_number=4),
 ]
 
@@ -1934,16 +1931,16 @@ def _prepare_test_cases():
   make_inst(opname='LOAD_CONST', arg=3, argval='Never reach this', 
argrepr="'Never reach this'", offset=292, start_offset=292, starts_line=False, 
line_number=26),
   make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=294, 
start_offset=294, starts_line=False, line_number=26, cache_info=[('counter', 1, 
b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
   make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=302, 
start_offset=302, starts_line=False, line_number=26),
-  make_inst(opname='LOAD_CONST', arg=4, argval=None, argrepr='None', 
offset=304, start_offset=304, starts_line=True, line_number=25),
-  make_inst(opname='LOAD_CONST', arg=4, argval=None, argrepr='None', 
offset=306, start_offset=306, starts_line=False, line_number=25),
-  make_inst(opname='LOAD_CONST', arg=4, argval=None, argrepr='None', 
offset=308, start_offset=308, starts_line=False, line_number=25),
+  make_inst(opname='LOAD_COMMON_CONSTANT', arg=7, argval=None, argrepr='None', 
offset=304, start_offset=304, starts_line=True, line_number=25),
+  make_inst(opname='LOAD_COMMON_CONSTANT', arg=7, argval=None, argrepr='None', 
offset=306, start_offset=306, starts_line=False, line_number=25),
+  make_inst(opname='LOAD_COMMON_CONSTANT', arg=7, argval=None, argrepr='None', 
offset=308, start_offset=308, starts_line=False, line_number=25),
   make_inst(opname='CALL', arg=3, argval=3, argrepr='', offset=310, 
start_offset=310, starts_line=False, line_number=25, cache_info=[('counter', 1, 
b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
   make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=318, 
start_offset=318, starts_line=False, line_number=25),
   make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + 
NULL', offset=320, start_offset=320, starts_line=True, line_number=28, 
label=10, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), 
('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, 
b'\x00\x00')]),
-  make_inst(opname='LOAD_CONST', arg=6, argval="OK, now we're done", 
argrepr='"OK, now we\'re done"', offset=330, start_offset=330, 
starts_line=False, line_number=28),
+  make_inst(opname='LOAD_CONST', arg=5, argval="OK, now we're done", 
argrepr='"OK, now we\'re done"', offset=330, start_offset=330, 
starts_line=False, line_number=28),
   make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=332, 
start_offset=332, starts_line=False, line_number=28, cache_info=[('counter', 1, 
b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
   make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=340, 
start_offset=340, starts_line=False, line_number=28),
-  make_inst(opname='LOAD_CONST', arg=4, argval=None, argrepr='None', 
offset=342, start_offset=342, starts_line=False, line_number=28),
+  make_inst(opname='LOAD_COMMON_CONSTANT', arg=7, argval=None, argrepr='None', 
offset=342, start_offset=342, starts_line=False, line_number=28),
   make_inst(opname='RETURN_VALUE', arg=None, argval=None, argrepr='', 
offset=344, start_offset=344, starts_line=False, line_number=28),
   make_inst(opname='PUSH_EXC_INFO', arg=None, argval=None, argrepr='', 
offset=346, start_offset=346, starts_line=True, line_number=25),
   make_inst(opname='WITH_EXCEPT_START', arg=None, argval=None, argrepr='', 
offset=348, start_offset=348, starts_line=False, line_number=25),
@@ -1967,7 +1964,7 @@ def _prepare_test_cases():
   make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=402, 
start_offset=402, starts_line=False, line_number=22),
   make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=404, 
start_offset=404, starts_line=False, line_number=22),
   make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + 
NULL', offset=406, start_offset=406, starts_line=True, line_number=23, 
cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), 
('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, 
b'\x00\x00')]),
-  make_inst(opname='LOAD_CONST', arg=5, argval='Here we go, here we go, here 
we go...', argrepr="'Here we go, here we go, here we go...'", offset=416, 
start_offset=416, starts_line=False, line_number=23),
+  make_inst(opname='LOAD_CONST', arg=4, argval='Here we go, here we go, here 
we go...', argrepr="'Here we go, here we go, here we go...'", offset=416, 
start_offset=416, starts_line=False, line_number=23),
   make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=418, 
start_offset=418, starts_line=False, line_number=23, cache_info=[('counter', 1, 
b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
   make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=426, 
start_offset=426, starts_line=False, line_number=23),
   make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', 
offset=428, start_offset=428, starts_line=False, line_number=23),
@@ -1978,7 +1975,7 @@ def _prepare_test_cases():
   make_inst(opname='RERAISE', arg=1, argval=1, argrepr='', offset=438, 
start_offset=438, starts_line=False, line_number=None),
   make_inst(opname='PUSH_EXC_INFO', arg=None, argval=None, argrepr='', 
offset=440, start_offset=440, starts_line=False, line_number=None),
   make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + 
NULL', offset=442, start_offset=442, starts_line=True, line_number=28, 
cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), 
('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, 
b'\x00\x00')]),
-  make_inst(opname='LOAD_CONST', arg=6, argval="OK, now we're done", 
argrepr='"OK, now we\'re done"', offset=452, start_offset=452, 
starts_line=False, line_number=28),
+  make_inst(opname='LOAD_CONST', arg=5, argval="OK, now we're done", 
argrepr='"OK, now we\'re done"', offset=452, start_offset=452, 
starts_line=False, line_number=28),
   make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=454, 
start_offset=454, starts_line=False, line_number=28, cache_info=[('counter', 1, 
b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
   make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=462, 
start_offset=462, starts_line=False, line_number=28),
   make_inst(opname='RERAISE', arg=0, argval=0, argrepr='', offset=464, 
start_offset=464, starts_line=False, line_number=28),
@@ -1991,7 +1988,7 @@ def _prepare_test_cases():
 def simple(): pass
 expected_opinfo_simple = [
   make_inst(opname='RESUME', arg=0, argval=0, argrepr='', offset=0, 
start_offset=0, starts_line=True, line_number=simple.__code__.co_firstlineno),
-  make_inst(opname='LOAD_CONST', arg=0, argval=None, argrepr='None', offset=4, 
start_offset=4, starts_line=False, line_number=simple.__code__.co_firstlineno),
+  make_inst(opname='LOAD_COMMON_CONSTANT', arg=7, argval=None, argrepr='None', 
offset=4, start_offset=4, starts_line=False, 
line_number=simple.__code__.co_firstlineno),
   make_inst(opname='RETURN_VALUE', arg=None, argval=None, argrepr='', 
offset=6, start_offset=6, starts_line=False, 
line_number=simple.__code__.co_firstlineno),
 ]
 
@@ -2600,7 +2597,7 @@ def test_show_cache(self):
                         CACHE                    0 (func_version: 0)
                         CACHE                    0
                         POP_TOP
-                        LOAD_CONST               0 (None)
+                        LOAD_COMMON_CONSTANT     7 (None)
                         RETURN_VALUE
         '''
         for flag in ['-C', '--show-caches']:
@@ -2612,7 +2609,7 @@ def test_show_offsets(self):
         expect = '''
             0          0       RESUME                   0
 
-            1          4       LOAD_CONST               0 (None)
+            1          4       LOAD_COMMON_CONSTANT     7 (None)
                        6       RETURN_VALUE
         '''
         for flag in ['-O', '--show-offsets']:
@@ -2624,7 +2621,7 @@ def test_show_positions(self):
         expect = '''
             0:0-1:0            RESUME                   0
 
-            1:0-1:4            LOAD_CONST               0 (None)
+            1:0-1:4            LOAD_COMMON_CONSTANT     7 (None)
             1:0-1:4            RETURN_VALUE
         '''
         for flag in ['-P', '--show-positions']:
@@ -2636,7 +2633,7 @@ def test_specialized_code(self):
         expect = '''
             0           RESUME                   0
 
-            1           LOAD_CONST               0 (None)
+            1           LOAD_COMMON_CONSTANT     7 (None)
                         RETURN_VALUE
         '''
         for flag in ['-S', '--specialized']:
diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py
index abb071451d8b59..d44e61f25f7f55 100644
--- a/Lib/test/test_peepholer.py
+++ b/Lib/test/test_peepholer.py
@@ -106,7 +106,7 @@ def test_elim_inversion_of_is_or_in(self):
                 self.check_lnotab(code)
 
     def test_global_as_constant(self):
-        # LOAD_GLOBAL None/True/False  -->  LOAD_CONST None/True/False
+        # LOAD_GLOBAL None/True/False  -->  LOAD_COMMON_CONSTANT 
None/True/False
         def f():
             x = None
             x = None
@@ -121,7 +121,7 @@ def h():
         for func, elem in ((f, None), (g, True), (h, False)):
             with self.subTest(func=func):
                 self.assertNotInBytecode(func, 'LOAD_GLOBAL')
-                self.assertInBytecode(func, 'LOAD_CONST', elem)
+                self.assertInBytecode(func, 'LOAD_COMMON_CONSTANT', elem)
                 self.check_lnotab(func)
 
         def f():
@@ -129,7 +129,7 @@ def f():
             return None
 
         self.assertNotInBytecode(f, 'LOAD_GLOBAL')
-        self.assertInBytecode(f, 'LOAD_CONST', None)
+        self.assertInBytecode(f, 'LOAD_COMMON_CONSTANT', None)
         self.check_lnotab(f)
 
     def test_while_one(self):
@@ -146,13 +146,14 @@ def f():
 
     def test_pack_unpack(self):
         for line, elem in (
-            ('a, = a,', 'LOAD_CONST',),
+            ('a, = a,', None),
             ('a, b = a, b', 'SWAP',),
             ('a, b, c = a, b, c', 'SWAP',),
             ):
             with self.subTest(line=line):
                 code = compile(line,'','single')
-                self.assertInBytecode(code, elem)
+                if elem is not None:
+                    self.assertInBytecode(code, elem)
                 self.assertNotInBytecode(code, 'BUILD_TUPLE')
                 self.assertNotInBytecode(code, 'UNPACK_SEQUENCE')
                 self.check_lnotab(code)
@@ -174,10 +175,10 @@ def test_constant_folding_tuples_of_constants(self):
         # Long tuples should be folded too.
         code = compile(repr(tuple(range(10000))),'','single')
         self.assertNotInBytecode(code, 'BUILD_TUPLE')
-        # One LOAD_CONST for the tuple, one for the None return value
+        # One LOAD_CONST for the tuple; None return value uses 
LOAD_COMMON_CONSTANT
         load_consts = [instr for instr in dis.get_instructions(code)
                               if instr.opname == 'LOAD_CONST']
-        self.assertEqual(len(load_consts), 2)
+        self.assertEqual(len(load_consts), 1)
         self.check_lnotab(code)
 
         # Bug 1053819:  Tuple of constants misidentified when presented with:
@@ -283,11 +284,11 @@ def test_constant_folding_unaryop(self):
             ('-0.0', 'UNARY_NEGATIVE', None, True, 'LOAD_CONST', -0.0),
             ('-(1.0-1.0)', 'UNARY_NEGATIVE', None, True, 'LOAD_CONST', -0.0),
             ('-0.5', 'UNARY_NEGATIVE', None, True, 'LOAD_CONST', -0.5),
-            ('---1', 'UNARY_NEGATIVE', None, True, 'LOAD_CONST', -1),
+            ('---1', 'UNARY_NEGATIVE', None, True, 'LOAD_COMMON_CONSTANT', -1),
             ('---""', 'UNARY_NEGATIVE', None, False, None, None),
             ('~~~1', 'UNARY_INVERT', None, True, 'LOAD_CONST', -2),
             ('~~~""', 'UNARY_INVERT', None, False, None, None),
-            ('not not True', 'UNARY_NOT', None, True, 'LOAD_CONST', True),
+            ('not not True', 'UNARY_NOT', None, True, 'LOAD_COMMON_CONSTANT', 
True),
             ('not not x', 'UNARY_NOT', None, True, 'LOAD_NAME', 'x'),  # this 
should be optimized regardless of constant or not
             ('+++1', 'CALL_INTRINSIC_1', intrinsic_positive, True, 
'LOAD_SMALL_INT', 1),
             ('---x', 'UNARY_NEGATIVE', None, False, None, None),
@@ -326,7 +327,7 @@ def test_constant_folding_binop(self):
             ('1 + 2', 'NB_ADD', True, 'LOAD_SMALL_INT', 3),
             ('1 + 2 + 3', 'NB_ADD', True, 'LOAD_SMALL_INT', 6),
             ('1 + ""', 'NB_ADD', False, None, None),
-            ('1 - 2', 'NB_SUBTRACT', True, 'LOAD_CONST', -1),
+            ('1 - 2', 'NB_SUBTRACT', True, 'LOAD_COMMON_CONSTANT', -1),
             ('1 - 2 - 3', 'NB_SUBTRACT', True, 'LOAD_CONST', -4),
             ('1 - ""', 'NB_SUBTRACT', False, None, None),
             ('2 * 2', 'NB_MULTIPLY', True, 'LOAD_SMALL_INT', 4),
@@ -1539,7 +1540,7 @@ def test_optimize_literal_list_for_iter(self):
             end,
             ('END_FOR', None, 0),
             ('POP_ITER', None, 0),
-            ('LOAD_CONST', 0, 0),
+            ('LOAD_COMMON_CONSTANT', 7, 0),
             ('RETURN_VALUE', None, 0),
         ]
         self.cfg_optimization_test(before, after, consts=[None], 
expected_consts=[None, (1, 2)])
@@ -1572,7 +1573,7 @@ def test_optimize_literal_list_for_iter(self):
             end,
             ('END_FOR', None, 0),
             ('POP_ITER', None, 0),
-            ('LOAD_CONST', 0, 0),
+            ('LOAD_COMMON_CONSTANT', 7, 0),
             ('RETURN_VALUE', None, 0),
         ]
         self.cfg_optimization_test(before, after, consts=[None], 
expected_consts=[None])
@@ -1604,7 +1605,7 @@ def test_optimize_literal_set_for_iter(self):
             end,
             ('END_FOR', None, 0),
             ('POP_ITER', None, 0),
-            ('LOAD_CONST', 0, 0),
+            ('LOAD_COMMON_CONSTANT', 7, 0),
             ('RETURN_VALUE', None, 0),
         ]
         self.cfg_optimization_test(before, after, consts=[None], 
expected_consts=[None, frozenset({1, 2})])
@@ -1626,7 +1627,22 @@ def test_optimize_literal_set_for_iter(self):
             ('LOAD_CONST', 0, 0),
             ('RETURN_VALUE', None, 0),
         ]
-        self.cfg_optimization_test(same, same, consts=[None], 
expected_consts=[None])
+        expected = [
+            ('LOAD_SMALL_INT', 1, 0),
+            ('LOAD_NAME', 0, 0),
+            ('BUILD_SET', 2, 0),
+            ('GET_ITER', 0, 0),
+            start := self.Label(),
+            ('FOR_ITER', end := self.Label(), 0),
+            ('STORE_FAST', 0, 0),
+            ('JUMP', start, 0),
+            end,
+            ('END_FOR', None, 0),
+            ('POP_ITER', None, 0),
+            ('LOAD_COMMON_CONSTANT', 7, 0),
+            ('RETURN_VALUE', None, 0),
+        ]
+        self.cfg_optimization_test(same, expected, consts=[None], 
expected_consts=[None])
 
     def test_optimize_literal_list_contains(self):
         # x in [1, 2]  ==>  x in (1, 2)
@@ -1645,7 +1661,7 @@ def test_optimize_literal_list_contains(self):
             ('LOAD_CONST', 1, 0),
             ('CONTAINS_OP', 0, 0),
             ('POP_TOP', None, 0),
-            ('LOAD_CONST', 0, 0),
+            ('LOAD_COMMON_CONSTANT', 7, 0),
             ('RETURN_VALUE', None, 0),
         ]
         self.cfg_optimization_test(before, after, consts=[None], 
expected_consts=[None, (1, 2)])
@@ -1668,7 +1684,7 @@ def test_optimize_literal_list_contains(self):
             ('BUILD_TUPLE', 2, 0),
             ('CONTAINS_OP', 0, 0),
             ('POP_TOP', None, 0),
-            ('LOAD_CONST', 0, 0),
+            ('LOAD_COMMON_CONSTANT', 7, 0),
             ('RETURN_VALUE', None, 0),
         ]
         self.cfg_optimization_test(before, after, consts=[None], 
expected_consts=[None])
@@ -1690,7 +1706,7 @@ def test_optimize_literal_set_contains(self):
             ('LOAD_CONST', 1, 0),
             ('CONTAINS_OP', 0, 0),
             ('POP_TOP', None, 0),
-            ('LOAD_CONST', 0, 0),
+            ('LOAD_COMMON_CONSTANT', 7, 0),
             ('RETURN_VALUE', None, 0),
         ]
         self.cfg_optimization_test(before, after, consts=[None], 
expected_consts=[None, frozenset({1, 2})])
@@ -1707,7 +1723,17 @@ def test_optimize_literal_set_contains(self):
             ('LOAD_CONST', 0, 0),
             ('RETURN_VALUE', None, 0),
         ]
-        self.cfg_optimization_test(same, same, consts=[None], 
expected_consts=[None])
+        expected = [
+            ('LOAD_NAME', 0, 0),
+            ('LOAD_SMALL_INT', 1, 0),
+            ('LOAD_NAME', 1, 0),
+            ('BUILD_SET', 2, 0),
+            ('CONTAINS_OP', 0, 0),
+            ('POP_TOP', None, 0),
+            ('LOAD_COMMON_CONSTANT', 7, 0),
+            ('RETURN_VALUE', None, 0),
+        ]
+        self.cfg_optimization_test(same, expected, consts=[None], 
expected_consts=[None])
 
     def test_optimize_unary_not(self):
         # test folding
@@ -1718,10 +1744,10 @@ def test_optimize_unary_not(self):
             ('RETURN_VALUE', None, 0),
         ]
         after = [
-            ('LOAD_CONST', 1, 0),
+            ('LOAD_COMMON_CONSTANT', 10, 0),
             ('RETURN_VALUE', None, 0),
         ]
-        self.cfg_optimization_test(before, after, consts=[], 
expected_consts=[True, False])
+        self.cfg_optimization_test(before, after, consts=[], 
expected_consts=[True])
 
         # test cancel out
         before = [
@@ -1769,7 +1795,7 @@ def test_optimize_unary_not(self):
             ('RETURN_VALUE', None, 0),
         ]
         after = [
-            ('LOAD_CONST', 0, 0),
+            ('LOAD_COMMON_CONSTANT', 9, 0),
             ('RETURN_VALUE', None, 0),
         ]
         self.cfg_optimization_test(before, after, consts=[], 
expected_consts=[True])
@@ -1785,10 +1811,10 @@ def test_optimize_unary_not(self):
             ('RETURN_VALUE', None, 0),
         ]
         after = [
-            ('LOAD_CONST', 1, 0),
+            ('LOAD_COMMON_CONSTANT', 10, 0),
             ('RETURN_VALUE', None, 0),
         ]
-        self.cfg_optimization_test(before, after, consts=[], 
expected_consts=[True, False])
+        self.cfg_optimization_test(before, after, consts=[], 
expected_consts=[True])
 
         # test cancel out & eliminate to bool (to bool stays as we are not 
iterating to a fixed point)
         before = [
@@ -2430,7 +2456,7 @@ def test_list_to_tuple_get_iter(self):
             end,
             ("END_FOR", None, 11),
             ("POP_TOP", None, 12),
-            ("LOAD_CONST", 0, 13),
+            ("LOAD_COMMON_CONSTANT", 7, 13),
             ("RETURN_VALUE", None, 14),
         ]
         self.cfg_optimization_test(insts, expected_insts, consts=[None])
@@ -2454,7 +2480,7 @@ def make_bb(self, insts):
                 maxconst = max(maxconst, arg)
         consts = [None for _ in range(maxconst + 1)]
         return insts + [
-            ("LOAD_CONST", 0, last_loc + 1),
+            ("LOAD_COMMON_CONSTANT", 7, last_loc + 1),
             ("RETURN_VALUE", None, last_loc + 2),
         ], consts
 
@@ -2485,7 +2511,7 @@ def test_optimized(self):
         ]
         expected = [
             ("LOAD_FAST_BORROW", 0, 1),
-            ("LOAD_CONST", 1, 2),
+            ("LOAD_COMMON_CONSTANT", 7, 2),
             ("SWAP", 2, 3),
             ("POP_TOP", None, 4),
         ]
@@ -2523,7 +2549,13 @@ def test_unoptimized_if_support_killed(self):
             ("STORE_FAST", 0, 3),
             ("POP_TOP", None, 4),
         ]
-        self.check(insts, insts)
+        expected = [
+            ("LOAD_FAST", 0, 1),
+            ("LOAD_COMMON_CONSTANT", 7, 2),
+            ("STORE_FAST", 0, 3),
+            ("POP_TOP", None, 4),
+        ]
+        self.check(insts, expected)
 
         insts = [
             ("LOAD_FAST", 0, 1),
@@ -2532,7 +2564,14 @@ def test_unoptimized_if_support_killed(self):
             ("STORE_FAST_STORE_FAST", ((0 << 4) | 1), 4),
             ("POP_TOP", None, 5),
         ]
-        self.check(insts, insts)
+        expected = [
+            ("LOAD_FAST", 0, 1),
+            ("LOAD_COMMON_CONSTANT", 7, 2),
+            ("LOAD_COMMON_CONSTANT", 7, 3),
+            ("STORE_FAST_STORE_FAST", ((0 << 4) | 1), 4),
+            ("POP_TOP", None, 5),
+        ]
+        self.check(insts, expected)
 
         insts = [
             ("LOAD_FAST", 0, 1),
@@ -2553,7 +2592,12 @@ def test_unoptimized_if_aliased(self):
             ("LOAD_CONST", 0, 3),
             ("STORE_FAST_STORE_FAST", ((0 << 4) | 1), 4),
         ]
-        self.check(insts, insts)
+        expected = [
+            ("LOAD_FAST", 0, 1),
+            ("LOAD_COMMON_CONSTANT", 7, 3),
+            ("STORE_FAST_STORE_FAST", ((0 << 4) | 1), 4),
+        ]
+        self.check(insts, expected)
 
     def test_consume_no_inputs(self):
         insts = [
@@ -2598,7 +2642,19 @@ def test_for_iter(self):
             ("LOAD_CONST", 0, 7),
             ("RETURN_VALUE", None, 8),
         ]
-        self.cfg_optimization_test(insts, insts, consts=[None])
+        expected = [
+            ("LOAD_FAST", 0, 1),
+            top := self.Label(),
+            ("FOR_ITER", end := self.Label(), 2),
+            ("STORE_FAST", 2, 3),
+            ("JUMP", top, 4),
+            end,
+            ("END_FOR", None, 5),
+            ("POP_TOP", None, 6),
+            ("LOAD_COMMON_CONSTANT", 7, 7),
+            ("RETURN_VALUE", None, 8),
+        ]
+        self.cfg_optimization_test(insts, expected, consts=[None])
 
     def test_load_attr(self):
         insts = [
@@ -2667,10 +2723,10 @@ def test_send(self):
             ("LOAD_FAST", 0, 1),
             ("LOAD_FAST_BORROW", 1, 2),
             ("SEND", end := self.Label(), 3),
-            ("LOAD_CONST", 0, 4),
+            ("LOAD_COMMON_CONSTANT", 7, 4),
             ("RETURN_VALUE", None, 5),
             end,
-            ("LOAD_CONST", 0, 6),
+            ("LOAD_COMMON_CONSTANT", 7, 6),
             ("RETURN_VALUE", None, 7)
         ]
         self.cfg_optimization_test(insts, expected, consts=[None])
@@ -2708,7 +2764,15 @@ def test_set_function_attribute(self):
             ("LOAD_CONST", 0, 5),
             ("RETURN_VALUE", None, 6)
         ]
-        self.cfg_optimization_test(insts, insts, consts=[None])
+        expected = [
+            ("LOAD_COMMON_CONSTANT", 7, 1),
+            ("LOAD_FAST", 0, 2),
+            ("SET_FUNCTION_ATTRIBUTE", 2, 3),
+            ("STORE_FAST", 1, 4),
+            ("LOAD_COMMON_CONSTANT", 7, 5),
+            ("RETURN_VALUE", None, 6)
+        ]
+        self.cfg_optimization_test(insts, expected, consts=[None])
 
         insts = [
             ("LOAD_CONST", 0, 1),
@@ -2717,7 +2781,7 @@ def test_set_function_attribute(self):
             ("RETURN_VALUE", None, 4)
         ]
         expected = [
-            ("LOAD_CONST", 0, 1),
+            ("LOAD_COMMON_CONSTANT", 7, 1),
             ("LOAD_FAST_BORROW", 0, 2),
             ("SET_FUNCTION_ATTRIBUTE", 2, 3),
             ("RETURN_VALUE", None, 4)
@@ -2740,7 +2804,22 @@ def test_get_yield_from_iter(self):
             ("LOAD_CONST", 0, 11),
             ("RETURN_VALUE", None, 12),
         ]
-        self.cfg_optimization_test(insts, insts, consts=[None])
+        expected = [
+            ("LOAD_FAST", 0, 1),
+            ("GET_ITER", 1, 2),
+            ("PUSH_NULL", None, 3),
+            ("LOAD_COMMON_CONSTANT", 7, 4),
+            send := self.Label(),
+            ("SEND", end := self.Label(), 6),
+            ("YIELD_VALUE", 1, 7),
+            ("RESUME", 2, 8),
+            ("JUMP", send, 9),
+            end,
+            ("END_SEND", None, 10),
+            ("LOAD_COMMON_CONSTANT", 7, 11),
+            ("RETURN_VALUE", None, 12),
+        ]
+        self.cfg_optimization_test(insts, expected, consts=[None])
 
     def test_push_exc_info(self):
         insts = [
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index 50ebe657a0eea6..8be85b1accbdca 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -2128,10 +2128,6 @@ code_returns_only_none(PyCodeObject *co)
     int len = (int)Py_SIZE(co);
     assert(len > 0);
 
-    // The last instruction either returns or raises.  We can take advantage
-    // of that for a quick exit.
-    _Py_CODEUNIT final = _Py_GetBaseCodeUnit(co, len-1);
-
     // Look up None in co_consts.
     Py_ssize_t nconsts = PyTuple_Size(co->co_consts);
     int none_index = 0;
@@ -2140,45 +2136,25 @@ code_returns_only_none(PyCodeObject *co)
             break;
         }
     }
-    if (none_index == nconsts) {
-        // None wasn't there, which means there was no implicit return,
-        // "return", or "return None".
-
-        // That means there must be
-        // an explicit return (non-None), or it only raises.
-        if (IS_RETURN_OPCODE(final.op.code)) {
-            // It was an explicit return (non-None).
-            return 0;
+    /* We don't worry about EXTENDED_ARG for now. */
+    for (int i = 0; i < len; i += _PyInstruction_GetLength(co, i)) {
+        _Py_CODEUNIT inst = _Py_GetBaseCodeUnit(co, i);
+        if (!IS_RETURN_OPCODE(inst.op.code)) {
+            continue;
         }
-        // It must end with a raise then.  We still have to walk the
-        // bytecode to see if there's any explicit return (non-None).
-        assert(IS_RAISE_OPCODE(final.op.code));
-        for (int i = 0; i < len; i += _PyInstruction_GetLength(co, i)) {
-            _Py_CODEUNIT inst = _Py_GetBaseCodeUnit(co, i);
-            if (IS_RETURN_OPCODE(inst.op.code)) {
-                // We alraedy know it isn't returning None.
-                return 0;
-            }
+        assert(i != 0);
+        _Py_CODEUNIT prev = _Py_GetBaseCodeUnit(co, i-1);
+        if (prev.op.code == LOAD_COMMON_CONSTANT &&
+            prev.op.arg == CONSTANT_NONE)
+        {
+            continue;
         }
-        // It must only raise.
-    }
-    else {
-        // Walk the bytecode, looking for RETURN_VALUE.
-        for (int i = 0; i < len; i += _PyInstruction_GetLength(co, i)) {
-            _Py_CODEUNIT inst = _Py_GetBaseCodeUnit(co, i);
-            if (IS_RETURN_OPCODE(inst.op.code)) {
-                assert(i != 0);
-                // Ignore it if it returns None.
-                _Py_CODEUNIT prev = _Py_GetBaseCodeUnit(co, i-1);
-                if (prev.op.code == LOAD_CONST) {
-                    // We don't worry about EXTENDED_ARG for now.
-                    if (prev.op.arg == none_index) {
-                        continue;
-                    }
-                }
-                return 0;
-            }
+        if (none_index < nconsts && prev.op.code == LOAD_CONST
+            && prev.op.arg == none_index)
+        {
+            continue;
         }
+        return 0;
     }
     return 1;
 }
diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h
index 28e08e42f5c88f..1bcf98a7600851 100644
--- a/Programs/test_frozenmain.h
+++ b/Programs/test_frozenmain.h
@@ -2,38 +2,38 @@
 unsigned char M_test_frozenmain[] = {
     227,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,
     0,0,0,0,0,243,188,0,0,0,128,0,0,0,93,0,
-    81,1,72,0,115,0,93,0,81,1,72,4,115,1,92,2,
-    31,0,81,2,50,1,0,0,0,0,0,0,29,0,92,2,
-    31,0,81,3,92,0,79,6,0,0,0,0,0,0,0,0,
+    80,7,72,0,115,0,93,0,80,7,72,4,115,1,92,2,
+    31,0,81,1,50,1,0,0,0,0,0,0,29,0,92,2,
+    31,0,81,2,92,0,79,6,0,0,0,0,0,0,0,0,
     0,0,0,0,0,0,0,0,0,0,50,2,0,0,0,0,
     0,0,29,0,92,1,79,8,0,0,0,0,0,0,0,0,
     0,0,0,0,0,0,0,0,0,0,31,0,50,0,0,0,
-    0,0,0,0,81,4,42,26,0,0,0,0,0,0,0,0,
-    0,0,115,5,81,7,70,0,0,0,68,24,0,0,115,6,
-    92,2,31,0,81,5,92,6,12,0,81,6,92,5,92,6,
+    0,0,0,0,81,3,42,26,0,0,0,0,0,0,0,0,
+    0,0,115,5,81,6,70,0,0,0,68,24,0,0,115,6,
+    92,2,31,0,81,4,92,6,12,0,81,5,92,5,92,6,
     42,26,0,0,0,0,0,0,0,0,0,0,12,0,48,4,
     50,1,0,0,0,0,0,0,29,0,74,26,0,0,9,0,
-    28,0,81,1,33,0,41,8,233,0,0,0,0,78,122,18,
-    70,114,111,122,101,110,32,72,101,108,108,111,32,87,111,114,
-    108,100,122,8,115,121,115,46,97,114,103,118,218,6,99,111,
-    110,102,105,103,122,7,99,111,110,102,105,103,32,122,2,58,
-    32,41,5,218,12,112,114,111,103,114,97,109,95,110,97,109,
-    101,218,10,101,120,101,99,117,116,97,98,108,101,218,15,117,
-    115,101,95,101,110,118,105,114,111,110,109,101,110,116,218,17,
-    99,111,110,102,105,103,117,114,101,95,99,95,115,116,100,105,
-    111,218,14,98,117,102,102,101,114,101,100,95,115,116,100,105,
-    111,41,7,218,3,115,121,115,218,17,95,116,101,115,116,105,
-    110,116,101,114,110,97,108,99,97,112,105,218,5,112,114,105,
-    110,116,218,4,97,114,103,118,218,11,103,101,116,95,99,111,
-    110,102,105,103,115,114,3,0,0,0,218,3,107,101,121,169,
-    0,243,0,0,0,0,218,18,116,101,115,116,95,102,114,111,
-    122,101,110,109,97,105,110,46,112,121,218,8,60,109,111,100,
-    117,108,101,62,114,18,0,0,0,1,0,0,0,115,94,0,
-    0,0,241,3,1,1,1,243,8,0,1,11,219,0,24,225,
-    0,5,208,6,26,212,0,27,217,0,5,128,106,144,35,151,
-    40,145,40,212,0,27,216,9,26,215,9,38,210,9,38,211,
-    9,40,168,24,213,9,50,128,6,244,2,6,12,2,128,67,
-    241,14,0,5,10,136,71,144,67,144,53,152,2,152,54,160,
-    35,157,59,152,45,208,10,40,214,4,41,243,15,6,12,2,
-    114,16,0,0,0,
+    28,0,80,7,33,0,41,7,233,0,0,0,0,122,18,70,
+    114,111,122,101,110,32,72,101,108,108,111,32,87,111,114,108,
+    100,122,8,115,121,115,46,97,114,103,118,218,6,99,111,110,
+    102,105,103,122,7,99,111,110,102,105,103,32,122,2,58,32,
+    41,5,218,12,112,114,111,103,114,97,109,95,110,97,109,101,
+    218,10,101,120,101,99,117,116,97,98,108,101,218,15,117,115,
+    101,95,101,110,118,105,114,111,110,109,101,110,116,218,17,99,
+    111,110,102,105,103,117,114,101,95,99,95,115,116,100,105,111,
+    218,14,98,117,102,102,101,114,101,100,95,115,116,100,105,111,
+    41,7,218,3,115,121,115,218,17,95,116,101,115,116,105,110,
+    116,101,114,110,97,108,99,97,112,105,218,5,112,114,105,110,
+    116,218,4,97,114,103,118,218,11,103,101,116,95,99,111,110,
+    102,105,103,115,114,3,0,0,0,218,3,107,101,121,169,0,
+    243,0,0,0,0,218,18,116,101,115,116,95,102,114,111,122,
+    101,110,109,97,105,110,46,112,121,218,8,60,109,111,100,117,
+    108,101,62,114,18,0,0,0,1,0,0,0,115,94,0,0,
+    0,241,3,1,1,1,243,8,0,1,11,219,0,24,225,0,
+    5,208,6,26,212,0,27,217,0,5,128,106,144,35,151,40,
+    145,40,212,0,27,216,9,26,215,9,38,210,9,38,211,9,
+    40,168,24,213,9,50,128,6,244,2,6,12,2,128,67,241,
+    14,0,5,10,136,71,144,67,144,53,152,2,152,54,160,35,
+    157,59,152,45,208,10,40,214,4,41,243,15,6,12,2,114,
+    16,0,0,0,
 };
diff --git a/Python/flowgraph.c b/Python/flowgraph.c
index 2cb2d32a410613..224426b7aa44bc 100644
--- a/Python/flowgraph.c
+++ b/Python/flowgraph.c
@@ -10,6 +10,7 @@
 
 #include "pycore_opcode_utils.h"
 #include "pycore_opcode_metadata.h" // OPCODE_HAS_ARG, etc
+#include "pycore_pystate.h"         // _PyInterpreterState_GET()
 
 #include <stdbool.h>
 
@@ -1125,6 +1126,8 @@ remove_redundant_nops(cfg_builder *g) {
     return changes;
 }
 
+static int loads_const(int opcode);
+
 static int
 remove_redundant_nops_and_pairs(basicblock *entryblock)
 {
@@ -1148,7 +1151,7 @@ remove_redundant_nops_and_pairs(basicblock *entryblock)
                 int opcode = instr->i_opcode;
                 bool is_redundant_pair = false;
                 if (opcode == POP_TOP) {
-                   if (prev_opcode == LOAD_CONST || prev_opcode == 
LOAD_SMALL_INT) {
+                   if (loads_const(prev_opcode)) {
                        is_redundant_pair = true;
                    }
                    else if (prev_opcode == COPY && prev_oparg == 1) {
@@ -1300,7 +1303,9 @@ jump_thread(basicblock *bb, cfg_instr *inst, cfg_instr 
*target, int opcode)
 static int
 loads_const(int opcode)
 {
-    return OPCODE_HAS_CONST(opcode) || opcode == LOAD_SMALL_INT;
+    return OPCODE_HAS_CONST(opcode)
+        || opcode == LOAD_SMALL_INT
+        || opcode == LOAD_COMMON_CONSTANT;
 }
 
 /* Returns new reference */
@@ -1323,6 +1328,10 @@ get_const_value(int opcode, int oparg, PyObject 
*co_consts)
     if (opcode == LOAD_SMALL_INT) {
         return PyLong_FromLong(oparg);
     }
+    if (opcode == LOAD_COMMON_CONSTANT) {
+        assert(oparg < NUM_COMMON_CONSTANTS);
+        return Py_NewRef(_PyInterpreterState_GET()->common_consts[oparg]);
+    }
 
     if (constant == NULL) {
         PyErr_SetString(PyExc_SystemError,
@@ -1437,6 +1446,46 @@ maybe_instr_make_load_smallint(cfg_instr *instr, 
PyObject *newconst,
     return 0;
 }
 
+/* Does not steal reference to "newconst".
+   Return 1 if changed instruction to LOAD_COMMON_CONSTANT.
+   Return 0 if could not change instruction to LOAD_COMMON_CONSTANT.
+   Return -1 on error.
+*/
+static int
+maybe_instr_make_load_common_const(cfg_instr *instr, PyObject *newconst)
+{
+    int oparg;
+    if (newconst == Py_None) {
+        oparg = CONSTANT_NONE;
+    }
+    else if (newconst == Py_True) {
+        oparg = CONSTANT_TRUE;
+    }
+    else if (newconst == Py_False) {
+        oparg = CONSTANT_FALSE;
+    }
+    else if (PyUnicode_CheckExact(newconst)
+             && PyUnicode_GET_LENGTH(newconst) == 0) {
+        oparg = CONSTANT_EMPTY_STR;
+    }
+    else if (PyLong_CheckExact(newconst)) {
+        int overflow;
+        long val = PyLong_AsLongAndOverflow(newconst, &overflow);
+        if (val == -1 && PyErr_Occurred()) {
+            return -1;
+        }
+        if (overflow || val != -1) {
+            return 0;
+        }
+        oparg = CONSTANT_MINUS_ONE;
+    }
+    else {
+        return 0;
+    }
+    assert(_Py_IsImmortal(newconst));
+    INSTR_SET_OP1(instr, LOAD_COMMON_CONSTANT, oparg);
+    return 1;
+}
 
 /* Steals reference to "newconst" */
 static int
@@ -1452,6 +1501,14 @@ instr_make_load_const(cfg_instr *instr, PyObject 
*newconst,
     if (res > 0) {
         return SUCCESS;
     }
+    res = maybe_instr_make_load_common_const(instr, newconst);
+    if (res < 0) {
+        Py_DECREF(newconst);
+        return ERROR;
+    }
+    if (res > 0) {
+        return SUCCESS;
+    }
     int oparg = add_const(newconst, consts, const_cache, consts_index);
     RETURN_IF_ERROR(oparg);
     INSTR_SET_OP1(instr, LOAD_CONST, oparg);
@@ -2208,7 +2265,7 @@ basicblock_optimize_load_const(PyObject *const_cache, 
basicblock *bb,
             oparg = inst->i_oparg;
         }
         assert(!IS_ASSEMBLER_OPCODE(opcode));
-        if (opcode != LOAD_CONST && opcode != LOAD_SMALL_INT) {
+        if (!loads_const(opcode)) {
             continue;
         }
         int nextop = i+1 < bb->b_iused ? bb->b_instr[i+1].i_opcode : 0;
@@ -2308,6 +2365,17 @@ basicblock_optimize_load_const(PyObject *const_cache, 
basicblock *bb,
                 break;
             }
         }
+        if (inst->i_opcode == LOAD_CONST) {
+            PyObject *constant = get_const_value(inst->i_opcode, 
inst->i_oparg, consts);
+            if (constant == NULL) {
+                return ERROR;
+            }
+            int res = maybe_instr_make_load_common_const(inst, constant);
+            Py_DECREF(constant);
+            if (res < 0) {
+                return ERROR;
+            }
+        }
     }
     return SUCCESS;
 }
diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c
index 83ecbf0ec12907..fa34fe4cbb3417 100644
--- a/Python/optimizer_bytecodes.c
+++ b/Python/optimizer_bytecodes.c
@@ -1,4 +1,6 @@
 #include "Python.h"
+#include "pycore_long.h"
+#include "pycore_opcode_utils.h"
 #include "pycore_optimizer.h"
 #include "pycore_uops.h"
 #include "pycore_uop_ids.h"
@@ -875,8 +877,14 @@ dummy_func(void) {
     op(_LOAD_COMMON_CONSTANT, (-- value)) {
         assert(oparg < NUM_COMMON_CONSTANTS);
         PyObject *val = _PyInterpreterState_GET()->common_consts[oparg];
-        ADD_OP(_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val);
-        value = PyJitRef_Borrow(sym_new_const(ctx, val));
+        if (_Py_IsImmortal(val)) {
+            ADD_OP(_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val);
+            value = PyJitRef_Borrow(sym_new_const(ctx, val));
+        }
+        else {
+            ADD_OP(_LOAD_CONST_INLINE, 0, (uintptr_t)val);
+            value = sym_new_const(ctx, val);
+        }
     }
 
     op(_LOAD_SMALL_INT, (-- value)) {
diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h
index 39e98634a6e9c2..553bd7302026f0 100644
--- a/Python/optimizer_cases.c.h
+++ b/Python/optimizer_cases.c.h
@@ -1911,8 +1911,14 @@
             JitOptRef value;
             assert(oparg < NUM_COMMON_CONSTANTS);
             PyObject *val = _PyInterpreterState_GET()->common_consts[oparg];
-            ADD_OP(_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val);
-            value = PyJitRef_Borrow(sym_new_const(ctx, val));
+            if (_Py_IsImmortal(val)) {
+                ADD_OP(_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val);
+                value = PyJitRef_Borrow(sym_new_const(ctx, val));
+            }
+            else {
+                ADD_OP(_LOAD_CONST_INLINE, 0, (uintptr_t)val);
+                value = sym_new_const(ctx, val);
+            }
             CHECK_STACK_BOUNDS(1);
             stack_pointer[0] = value;
             stack_pointer += 1;
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 57ce519c3c10ef..728c0acdd4df67 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -879,13 +879,19 @@ pycore_init_builtins(PyThreadState *tstate)
 
     interp->common_consts[CONSTANT_ASSERTIONERROR] = PyExc_AssertionError;
     interp->common_consts[CONSTANT_NOTIMPLEMENTEDERROR] = 
PyExc_NotImplementedError;
-    interp->common_consts[CONSTANT_BUILTIN_TUPLE] = (PyObject*)&PyTuple_Type;
+    interp->common_consts[CONSTANT_BUILTIN_TUPLE] = (PyObject *)&PyTuple_Type;
     interp->common_consts[CONSTANT_BUILTIN_ALL] = all;
     interp->common_consts[CONSTANT_BUILTIN_ANY] = any;
-    interp->common_consts[CONSTANT_BUILTIN_LIST] = (PyObject*)&PyList_Type;
-    interp->common_consts[CONSTANT_BUILTIN_SET] = (PyObject*)&PySet_Type;
-
-    for (int i=0; i < NUM_COMMON_CONSTANTS; i++) {
+    interp->common_consts[CONSTANT_BUILTIN_LIST] = (PyObject *)&PyList_Type;
+    interp->common_consts[CONSTANT_BUILTIN_SET] = (PyObject *)&PySet_Type;
+    interp->common_consts[CONSTANT_NONE] = Py_None;
+    interp->common_consts[CONSTANT_EMPTY_STR] =
+        Py_GetConstantBorrowed(Py_CONSTANT_EMPTY_STR);
+    interp->common_consts[CONSTANT_TRUE] = Py_True;
+    interp->common_consts[CONSTANT_FALSE] = Py_False;
+    interp->common_consts[CONSTANT_MINUS_ONE] =
+        (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS - 1];
+    for (int i = 0; i < NUM_COMMON_CONSTANTS; i++) {
         assert(interp->common_consts[i] != NULL);
     }
 

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to