]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-100239: specialize bitwise logical binary ops on ints (#128927)
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>
Wed, 29 Jan 2025 09:28:21 +0000 (09:28 +0000)
committerGitHub <noreply@github.com>
Wed, 29 Jan 2025 09:28:21 +0000 (09:28 +0000)
Include/internal/pycore_opcode_metadata.h
Include/internal/pycore_uop_metadata.h
Lib/test/test_opcache.py
Misc/NEWS.d/next/Core_and_Builtins/2025-01-16-22-54-12.gh-issue-100239.7_HpBU.rst [new file with mode: 0644]
Python/bytecodes.c
Python/specialize.c
Tools/c-analyzer/cpython/ignored.tsv

index 98dfead35f7c31a2215a340e24ed5f7301980825..fe791c090120c940fa071ad6ead61a016eeae5cc 100644 (file)
@@ -2013,7 +2013,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = {
     [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG },
     [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG },
     [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG },
-    [BINARY_OP_EXTEND] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
+    [BINARY_OP_EXTEND] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
     [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG },
     [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG },
     [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG },
index 59740dbb57072ea5f193f874f4e1a60eb2ac8ac7..80f89defb7e2eb611d71aecf688a38d984c12c66 100644 (file)
@@ -82,7 +82,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {
     [_GUARD_BOTH_UNICODE] = HAS_EXIT_FLAG,
     [_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_PURE_FLAG,
     [_BINARY_OP_INPLACE_ADD_UNICODE] = HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG,
-    [_GUARD_BINARY_OP_EXTEND] = HAS_EXIT_FLAG | HAS_ESCAPES_FLAG,
+    [_GUARD_BINARY_OP_EXTEND] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG,
     [_BINARY_OP_EXTEND] = HAS_ESCAPES_FLAG | HAS_PURE_FLAG,
     [_BINARY_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
     [_BINARY_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
index cc58a4b8c3cd112397d68e795d4a8af099cc1b44..dc02d1d7babb23eefb9e99a4c342e3bf1f7db6cc 100644 (file)
@@ -1396,6 +1396,29 @@ class TestSpecializer(TestBase):
 
         binary_op_nan()
 
+        def binary_op_bitwise_extend():
+            for _ in range(100):
+                a, b = 2, 7
+                x = a | b
+                self.assertEqual(x, 7)
+                y = a & b
+                self.assertEqual(y, 2)
+                z = a ^ b
+                self.assertEqual(z, 5)
+                a, b = 3, 9
+                a |= b
+                self.assertEqual(a, 11)
+                a, b = 11, 9
+                a &= b
+                self.assertEqual(a, 9)
+                a, b = 3, 9
+                a ^= b
+                self.assertEqual(a, 10)
+
+        binary_op_bitwise_extend()
+        self.assert_specialized(binary_op_bitwise_extend, "BINARY_OP_EXTEND")
+        self.assert_no_opcode(binary_op_bitwise_extend, "BINARY_OP")
+
     @cpython_only
     @requires_specialization_ft
     def test_load_super_attr(self):
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-01-16-22-54-12.gh-issue-100239.7_HpBU.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-16-22-54-12.gh-issue-100239.7_HpBU.rst
new file mode 100644 (file)
index 0000000..6f086b7
--- /dev/null
@@ -0,0 +1 @@
+Specialize ``BINARY_OP`` for bitwise logical operations on compact ints.
index 0d7b9f2a781019522a62144901aa21fc7bc000c4..f659a5e5c920a76bd0349b4db14b221ece1ca7bd 100644 (file)
@@ -759,7 +759,7 @@ dummy_func(
             assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5);
             assert(d && d->guard);
             int res = d->guard(left_o, right_o);
-            EXIT_IF(!res);
+            DEOPT_IF(!res);
         }
 
         pure op(_BINARY_OP_EXTEND, (descr/4, left, right -- res)) {
index fa022346bdea6aa57b6b2e968a51c2e04e4da6c7..abb130d73eeebd0efc66c0f52841df5d2c9b8dea 100644 (file)
@@ -581,6 +581,10 @@ _PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, PyObject *consts,
 #define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_FLOAT           26
 #define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER           27
 #define SPEC_FAIL_BINARY_OP_XOR                         28
+#define SPEC_FAIL_BINARY_OP_OR_INT                      29
+#define SPEC_FAIL_BINARY_OP_OR_DIFFERENT_TYPES          30
+#define SPEC_FAIL_BINARY_OP_XOR_INT                     31
+#define SPEC_FAIL_BINARY_OP_XOR_DIFFERENT_TYPES         32
 
 /* Calls */
 
@@ -2379,6 +2383,12 @@ binary_op_fail_kind(int oparg, PyObject *lhs, PyObject *rhs)
             return SPEC_FAIL_BINARY_OP_MULTIPLY_OTHER;
         case NB_OR:
         case NB_INPLACE_OR:
+            if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
+                return SPEC_FAIL_BINARY_OP_OR_DIFFERENT_TYPES;
+            }
+            if (PyLong_CheckExact(lhs)) {
+                return SPEC_FAIL_BINARY_OP_OR_INT;
+            }
             return SPEC_FAIL_BINARY_OP_OR;
         case NB_POWER:
         case NB_INPLACE_POWER:
@@ -2406,6 +2416,12 @@ binary_op_fail_kind(int oparg, PyObject *lhs, PyObject *rhs)
             return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER;
         case NB_XOR:
         case NB_INPLACE_XOR:
+            if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
+                return SPEC_FAIL_BINARY_OP_XOR_DIFFERENT_TYPES;
+            }
+            if (PyLong_CheckExact(lhs)) {
+                return SPEC_FAIL_BINARY_OP_XOR_INT;
+            }
             return SPEC_FAIL_BINARY_OP_XOR;
     }
     Py_UNREACHABLE();
@@ -2414,6 +2430,34 @@ binary_op_fail_kind(int oparg, PyObject *lhs, PyObject *rhs)
 
 /** Binary Op Specialization Extensions */
 
+/* long-long */
+
+static inline int
+is_compactlong(PyObject *v)
+{
+    return PyLong_CheckExact(v) &&
+           _PyLong_IsCompact((PyLongObject *)v);
+}
+
+static int
+compactlongs_guard(PyObject *lhs, PyObject *rhs)
+{
+    return (is_compactlong(lhs) && is_compactlong(rhs));
+}
+
+#define BITWISE_LONGS_ACTION(NAME, OP) \
+    static PyObject * \
+    (NAME)(PyObject *lhs, PyObject *rhs) \
+    { \
+        Py_ssize_t rhs_val = _PyLong_CompactValue((PyLongObject *)rhs); \
+        Py_ssize_t lhs_val = _PyLong_CompactValue((PyLongObject *)lhs); \
+        return PyLong_FromSsize_t(lhs_val OP rhs_val); \
+    }
+BITWISE_LONGS_ACTION(compactlongs_or, |)
+BITWISE_LONGS_ACTION(compactlongs_and, &)
+BITWISE_LONGS_ACTION(compactlongs_xor, ^)
+#undef BITWISE_LONGS_ACTION
+
 /* float-long */
 
 static inline int
@@ -2484,6 +2528,15 @@ LONG_FLOAT_ACTION(compactlong_float_multiply, *)
 LONG_FLOAT_ACTION(compactlong_float_true_div, /)
 #undef LONG_FLOAT_ACTION
 
+static _PyBinaryOpSpecializationDescr compactlongs_specs[NB_OPARG_LAST+1] = {
+    [NB_OR] = {compactlongs_guard, compactlongs_or},
+    [NB_AND] = {compactlongs_guard, compactlongs_and},
+    [NB_XOR] = {compactlongs_guard, compactlongs_xor},
+    [NB_INPLACE_OR] = {compactlongs_guard, compactlongs_or},
+    [NB_INPLACE_AND] = {compactlongs_guard, compactlongs_and},
+    [NB_INPLACE_XOR] = {compactlongs_guard, compactlongs_xor},
+};
+
 static _PyBinaryOpSpecializationDescr float_compactlong_specs[NB_OPARG_LAST+1] = {
     [NB_ADD] = {float_compactlong_guard, float_compactlong_add},
     [NB_SUBTRACT] = {float_compactlong_guard, float_compactlong_subtract},
@@ -2512,6 +2565,7 @@ binary_op_extended_specialization(PyObject *lhs, PyObject *rhs, int oparg,
 
     LOOKUP_SPEC(compactlong_float_specs, oparg);
     LOOKUP_SPEC(float_compactlong_specs, oparg);
+    LOOKUP_SPEC(compactlongs_specs, oparg);
 #undef LOOKUP_SPEC
     return 0;
 }
index 415d20e5b7fabb2e38b6804ba771ceb92f35e8f1..be3ded9f07ef8a0e4d0ee5792754c5ff4b6f543c 100644 (file)
@@ -381,6 +381,7 @@ Python/pylifecycle.c        -       INTERPRETER_TRAMPOLINE_CODEDEF  -
 Python/pystate.c       -       initial -
 Python/specialize.c    -       adaptive_opcodes        -
 Python/specialize.c    -       cache_requirements      -
+Python/specialize.c    -       compactlongs_specs      -
 Python/specialize.c    -       float_compactlong_specs -
 Python/specialize.c    -       compactlong_float_specs -
 Python/stdlib_module_names.h   -       _Py_stdlib_module_names -