]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-115687: Split up guards from COMPARE_OP (GH-115688)
authorKen Jin <kenjin@python.org>
Tue, 20 Feb 2024 11:30:49 +0000 (19:30 +0800)
committerGitHub <noreply@github.com>
Tue, 20 Feb 2024 11:30:49 +0000 (11:30 +0000)
Include/internal/pycore_opcode_metadata.h
Include/internal/pycore_uop_ids.h
Include/internal/pycore_uop_metadata.h
Lib/test/test_capi/test_opt.py
Python/bytecodes.c
Python/executor_cases.c.h
Python/generated_cases.c.h
Python/tier2_redundancy_eliminator_bytecodes.c
Python/tier2_redundancy_eliminator_cases.c.h

index f45e5f1901b0afbf2d38b3906ad4b1e6b4e7b01e..ab34366ab1066c4198453c71fc566a104413cf60 100644 (file)
@@ -999,9 +999,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = {
     [CHECK_EXC_MATCH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
     [CLEANUP_THROW] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
     [COMPARE_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
-    [COMPARE_OP_FLOAT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
-    [COMPARE_OP_INT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
-    [COMPARE_OP_STR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
+    [COMPARE_OP_FLOAT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
+    [COMPARE_OP_INT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
+    [COMPARE_OP_STR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
     [CONTAINS_OP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
     [CONVERT_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG },
     [COPY] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG },
@@ -1221,9 +1221,9 @@ _PyOpcode_macro_expansion[256] = {
     [CHECK_EG_MATCH] = { .nuops = 1, .uops = { { _CHECK_EG_MATCH, 0, 0 } } },
     [CHECK_EXC_MATCH] = { .nuops = 1, .uops = { { _CHECK_EXC_MATCH, 0, 0 } } },
     [COMPARE_OP] = { .nuops = 1, .uops = { { _COMPARE_OP, 0, 0 } } },
-    [COMPARE_OP_FLOAT] = { .nuops = 1, .uops = { { _COMPARE_OP_FLOAT, 0, 0 } } },
-    [COMPARE_OP_INT] = { .nuops = 1, .uops = { { _COMPARE_OP_INT, 0, 0 } } },
-    [COMPARE_OP_STR] = { .nuops = 1, .uops = { { _COMPARE_OP_STR, 0, 0 } } },
+    [COMPARE_OP_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _COMPARE_OP_FLOAT, 0, 0 } } },
+    [COMPARE_OP_INT] = { .nuops = 2, .uops = { { _GUARD_BOTH_INT, 0, 0 }, { _COMPARE_OP_INT, 0, 0 } } },
+    [COMPARE_OP_STR] = { .nuops = 2, .uops = { { _GUARD_BOTH_UNICODE, 0, 0 }, { _COMPARE_OP_STR, 0, 0 } } },
     [CONTAINS_OP] = { .nuops = 1, .uops = { { _CONTAINS_OP, 0, 0 } } },
     [CONVERT_VALUE] = { .nuops = 1, .uops = { { _CONVERT_VALUE, 0, 0 } } },
     [COPY] = { .nuops = 1, .uops = { { _COPY, 0, 0 } } },
index e098852d941f183efc90bbd575306a80bca73341..3c133d97b2f03ebf191837a3ab5426a337a0a5e8 100644 (file)
@@ -72,9 +72,9 @@ extern "C" {
 #define _CHECK_VALIDITY_AND_SET_IP 324
 #define _COLD_EXIT 325
 #define _COMPARE_OP 326
-#define _COMPARE_OP_FLOAT COMPARE_OP_FLOAT
-#define _COMPARE_OP_INT COMPARE_OP_INT
-#define _COMPARE_OP_STR COMPARE_OP_STR
+#define _COMPARE_OP_FLOAT 327
+#define _COMPARE_OP_INT 328
+#define _COMPARE_OP_STR 329
 #define _CONTAINS_OP CONTAINS_OP
 #define _CONVERT_VALUE CONVERT_VALUE
 #define _COPY COPY
@@ -89,41 +89,41 @@ extern "C" {
 #define _DICT_UPDATE DICT_UPDATE
 #define _END_SEND END_SEND
 #define _EXIT_INIT_CHECK EXIT_INIT_CHECK
-#define _FATAL_ERROR 327
+#define _FATAL_ERROR 330
 #define _FORMAT_SIMPLE FORMAT_SIMPLE
 #define _FORMAT_WITH_SPEC FORMAT_WITH_SPEC
-#define _FOR_ITER 328
+#define _FOR_ITER 331
 #define _FOR_ITER_GEN FOR_ITER_GEN
-#define _FOR_ITER_TIER_TWO 329
+#define _FOR_ITER_TIER_TWO 332
 #define _GET_AITER GET_AITER
 #define _GET_ANEXT GET_ANEXT
 #define _GET_AWAITABLE GET_AWAITABLE
 #define _GET_ITER GET_ITER
 #define _GET_LEN GET_LEN
 #define _GET_YIELD_FROM_ITER GET_YIELD_FROM_ITER
-#define _GUARD_BOTH_FLOAT 330
-#define _GUARD_BOTH_INT 331
-#define _GUARD_BOTH_UNICODE 332
-#define _GUARD_BUILTINS_VERSION 333
-#define _GUARD_DORV_VALUES 334
-#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 335
-#define _GUARD_GLOBALS_VERSION 336
-#define _GUARD_IS_FALSE_POP 337
-#define _GUARD_IS_NONE_POP 338
-#define _GUARD_IS_NOT_NONE_POP 339
-#define _GUARD_IS_TRUE_POP 340
-#define _GUARD_KEYS_VERSION 341
-#define _GUARD_NOT_EXHAUSTED_LIST 342
-#define _GUARD_NOT_EXHAUSTED_RANGE 343
-#define _GUARD_NOT_EXHAUSTED_TUPLE 344
-#define _GUARD_TYPE_VERSION 345
-#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 346
-#define _INIT_CALL_PY_EXACT_ARGS 347
-#define _INIT_CALL_PY_EXACT_ARGS_0 348
-#define _INIT_CALL_PY_EXACT_ARGS_1 349
-#define _INIT_CALL_PY_EXACT_ARGS_2 350
-#define _INIT_CALL_PY_EXACT_ARGS_3 351
-#define _INIT_CALL_PY_EXACT_ARGS_4 352
+#define _GUARD_BOTH_FLOAT 333
+#define _GUARD_BOTH_INT 334
+#define _GUARD_BOTH_UNICODE 335
+#define _GUARD_BUILTINS_VERSION 336
+#define _GUARD_DORV_VALUES 337
+#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 338
+#define _GUARD_GLOBALS_VERSION 339
+#define _GUARD_IS_FALSE_POP 340
+#define _GUARD_IS_NONE_POP 341
+#define _GUARD_IS_NOT_NONE_POP 342
+#define _GUARD_IS_TRUE_POP 343
+#define _GUARD_KEYS_VERSION 344
+#define _GUARD_NOT_EXHAUSTED_LIST 345
+#define _GUARD_NOT_EXHAUSTED_RANGE 346
+#define _GUARD_NOT_EXHAUSTED_TUPLE 347
+#define _GUARD_TYPE_VERSION 348
+#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 349
+#define _INIT_CALL_PY_EXACT_ARGS 350
+#define _INIT_CALL_PY_EXACT_ARGS_0 351
+#define _INIT_CALL_PY_EXACT_ARGS_1 352
+#define _INIT_CALL_PY_EXACT_ARGS_2 353
+#define _INIT_CALL_PY_EXACT_ARGS_3 354
+#define _INIT_CALL_PY_EXACT_ARGS_4 355
 #define _INSTRUMENTED_CALL INSTRUMENTED_CALL
 #define _INSTRUMENTED_CALL_FUNCTION_EX INSTRUMENTED_CALL_FUNCTION_EX
 #define _INSTRUMENTED_CALL_KW INSTRUMENTED_CALL_KW
@@ -140,65 +140,65 @@ extern "C" {
 #define _INSTRUMENTED_RETURN_CONST INSTRUMENTED_RETURN_CONST
 #define _INSTRUMENTED_RETURN_VALUE INSTRUMENTED_RETURN_VALUE
 #define _INSTRUMENTED_YIELD_VALUE INSTRUMENTED_YIELD_VALUE
-#define _INTERNAL_INCREMENT_OPT_COUNTER 353
-#define _IS_NONE 354
+#define _INTERNAL_INCREMENT_OPT_COUNTER 356
+#define _IS_NONE 357
 #define _IS_OP IS_OP
-#define _ITER_CHECK_LIST 355
-#define _ITER_CHECK_RANGE 356
-#define _ITER_CHECK_TUPLE 357
-#define _ITER_JUMP_LIST 358
-#define _ITER_JUMP_RANGE 359
-#define _ITER_JUMP_TUPLE 360
-#define _ITER_NEXT_LIST 361
-#define _ITER_NEXT_RANGE 362
-#define _ITER_NEXT_TUPLE 363
-#define _JUMP_TO_TOP 364
+#define _ITER_CHECK_LIST 358
+#define _ITER_CHECK_RANGE 359
+#define _ITER_CHECK_TUPLE 360
+#define _ITER_JUMP_LIST 361
+#define _ITER_JUMP_RANGE 362
+#define _ITER_JUMP_TUPLE 363
+#define _ITER_NEXT_LIST 364
+#define _ITER_NEXT_RANGE 365
+#define _ITER_NEXT_TUPLE 366
+#define _JUMP_TO_TOP 367
 #define _LIST_APPEND LIST_APPEND
 #define _LIST_EXTEND LIST_EXTEND
 #define _LOAD_ASSERTION_ERROR LOAD_ASSERTION_ERROR
-#define _LOAD_ATTR 365
-#define _LOAD_ATTR_CLASS 366
-#define _LOAD_ATTR_CLASS_0 367
-#define _LOAD_ATTR_CLASS_1 368
+#define _LOAD_ATTR 368
+#define _LOAD_ATTR_CLASS 369
+#define _LOAD_ATTR_CLASS_0 370
+#define _LOAD_ATTR_CLASS_1 371
 #define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN
-#define _LOAD_ATTR_INSTANCE_VALUE 369
-#define _LOAD_ATTR_INSTANCE_VALUE_0 370
-#define _LOAD_ATTR_INSTANCE_VALUE_1 371
-#define _LOAD_ATTR_METHOD_LAZY_DICT 372
-#define _LOAD_ATTR_METHOD_NO_DICT 373
-#define _LOAD_ATTR_METHOD_WITH_VALUES 374
-#define _LOAD_ATTR_MODULE 375
-#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 376
-#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 377
+#define _LOAD_ATTR_INSTANCE_VALUE 372
+#define _LOAD_ATTR_INSTANCE_VALUE_0 373
+#define _LOAD_ATTR_INSTANCE_VALUE_1 374
+#define _LOAD_ATTR_METHOD_LAZY_DICT 375
+#define _LOAD_ATTR_METHOD_NO_DICT 376
+#define _LOAD_ATTR_METHOD_WITH_VALUES 377
+#define _LOAD_ATTR_MODULE 378
+#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 379
+#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 380
 #define _LOAD_ATTR_PROPERTY LOAD_ATTR_PROPERTY
-#define _LOAD_ATTR_SLOT 378
-#define _LOAD_ATTR_SLOT_0 379
-#define _LOAD_ATTR_SLOT_1 380
-#define _LOAD_ATTR_WITH_HINT 381
+#define _LOAD_ATTR_SLOT 381
+#define _LOAD_ATTR_SLOT_0 382
+#define _LOAD_ATTR_SLOT_1 383
+#define _LOAD_ATTR_WITH_HINT 384
 #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS
 #define _LOAD_CONST LOAD_CONST
-#define _LOAD_CONST_INLINE 382
-#define _LOAD_CONST_INLINE_BORROW 383
-#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 384
-#define _LOAD_CONST_INLINE_WITH_NULL 385
+#define _LOAD_CONST_INLINE 385
+#define _LOAD_CONST_INLINE_BORROW 386
+#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 387
+#define _LOAD_CONST_INLINE_WITH_NULL 388
 #define _LOAD_DEREF LOAD_DEREF
-#define _LOAD_FAST 386
-#define _LOAD_FAST_0 387
-#define _LOAD_FAST_1 388
-#define _LOAD_FAST_2 389
-#define _LOAD_FAST_3 390
-#define _LOAD_FAST_4 391
-#define _LOAD_FAST_5 392
-#define _LOAD_FAST_6 393
-#define _LOAD_FAST_7 394
+#define _LOAD_FAST 389
+#define _LOAD_FAST_0 390
+#define _LOAD_FAST_1 391
+#define _LOAD_FAST_2 392
+#define _LOAD_FAST_3 393
+#define _LOAD_FAST_4 394
+#define _LOAD_FAST_5 395
+#define _LOAD_FAST_6 396
+#define _LOAD_FAST_7 397
 #define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR
 #define _LOAD_FAST_CHECK LOAD_FAST_CHECK
 #define _LOAD_FAST_LOAD_FAST LOAD_FAST_LOAD_FAST
 #define _LOAD_FROM_DICT_OR_DEREF LOAD_FROM_DICT_OR_DEREF
 #define _LOAD_FROM_DICT_OR_GLOBALS LOAD_FROM_DICT_OR_GLOBALS
-#define _LOAD_GLOBAL 395
-#define _LOAD_GLOBAL_BUILTINS 396
-#define _LOAD_GLOBAL_MODULE 397
+#define _LOAD_GLOBAL 398
+#define _LOAD_GLOBAL_BUILTINS 399
+#define _LOAD_GLOBAL_MODULE 400
 #define _LOAD_LOCALS LOAD_LOCALS
 #define _LOAD_NAME LOAD_NAME
 #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR
@@ -212,46 +212,46 @@ extern "C" {
 #define _MATCH_SEQUENCE MATCH_SEQUENCE
 #define _NOP NOP
 #define _POP_EXCEPT POP_EXCEPT
-#define _POP_FRAME 398
-#define _POP_JUMP_IF_FALSE 399
-#define _POP_JUMP_IF_TRUE 400
+#define _POP_FRAME 401
+#define _POP_JUMP_IF_FALSE 402
+#define _POP_JUMP_IF_TRUE 403
 #define _POP_TOP POP_TOP
 #define _PUSH_EXC_INFO PUSH_EXC_INFO
-#define _PUSH_FRAME 401
+#define _PUSH_FRAME 404
 #define _PUSH_NULL PUSH_NULL
 #define _RESUME_CHECK RESUME_CHECK
-#define _SAVE_RETURN_OFFSET 402
-#define _SEND 403
+#define _SAVE_RETURN_OFFSET 405
+#define _SEND 406
 #define _SEND_GEN SEND_GEN
 #define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS
 #define _SET_ADD SET_ADD
 #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE
 #define _SET_UPDATE SET_UPDATE
-#define _START_EXECUTOR 404
-#define _STORE_ATTR 405
-#define _STORE_ATTR_INSTANCE_VALUE 406
-#define _STORE_ATTR_SLOT 407
+#define _START_EXECUTOR 407
+#define _STORE_ATTR 408
+#define _STORE_ATTR_INSTANCE_VALUE 409
+#define _STORE_ATTR_SLOT 410
 #define _STORE_ATTR_WITH_HINT STORE_ATTR_WITH_HINT
 #define _STORE_DEREF STORE_DEREF
-#define _STORE_FAST 408
-#define _STORE_FAST_0 409
-#define _STORE_FAST_1 410
-#define _STORE_FAST_2 411
-#define _STORE_FAST_3 412
-#define _STORE_FAST_4 413
-#define _STORE_FAST_5 414
-#define _STORE_FAST_6 415
-#define _STORE_FAST_7 416
+#define _STORE_FAST 411
+#define _STORE_FAST_0 412
+#define _STORE_FAST_1 413
+#define _STORE_FAST_2 414
+#define _STORE_FAST_3 415
+#define _STORE_FAST_4 416
+#define _STORE_FAST_5 417
+#define _STORE_FAST_6 418
+#define _STORE_FAST_7 419
 #define _STORE_FAST_LOAD_FAST STORE_FAST_LOAD_FAST
 #define _STORE_FAST_STORE_FAST STORE_FAST_STORE_FAST
 #define _STORE_GLOBAL STORE_GLOBAL
 #define _STORE_NAME STORE_NAME
 #define _STORE_SLICE STORE_SLICE
-#define _STORE_SUBSCR 417
+#define _STORE_SUBSCR 420
 #define _STORE_SUBSCR_DICT STORE_SUBSCR_DICT
 #define _STORE_SUBSCR_LIST_INT STORE_SUBSCR_LIST_INT
 #define _SWAP SWAP
-#define _TO_BOOL 418
+#define _TO_BOOL 421
 #define _TO_BOOL_ALWAYS_TRUE TO_BOOL_ALWAYS_TRUE
 #define _TO_BOOL_BOOL TO_BOOL_BOOL
 #define _TO_BOOL_INT TO_BOOL_INT
@@ -262,12 +262,12 @@ extern "C" {
 #define _UNARY_NEGATIVE UNARY_NEGATIVE
 #define _UNARY_NOT UNARY_NOT
 #define _UNPACK_EX UNPACK_EX
-#define _UNPACK_SEQUENCE 419
+#define _UNPACK_SEQUENCE 422
 #define _UNPACK_SEQUENCE_LIST UNPACK_SEQUENCE_LIST
 #define _UNPACK_SEQUENCE_TUPLE UNPACK_SEQUENCE_TUPLE
 #define _UNPACK_SEQUENCE_TWO_TUPLE UNPACK_SEQUENCE_TWO_TUPLE
 #define _WITH_EXCEPT_START WITH_EXCEPT_START
-#define MAX_UOP_ID 419
+#define MAX_UOP_ID 422
 
 #ifdef __cplusplus
 }
index c9def0ecdc150161db2b16c35c76c4a0f33d86d2..35340fe9ee1b634161ab893fe393ebc5dc3f14c5 100644 (file)
@@ -149,9 +149,9 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {
     [_STORE_ATTR_INSTANCE_VALUE] = HAS_ESCAPES_FLAG,
     [_STORE_ATTR_SLOT] = HAS_ESCAPES_FLAG,
     [_COMPARE_OP] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
-    [_COMPARE_OP_FLOAT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG,
+    [_COMPARE_OP_FLOAT] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
     [_COMPARE_OP_INT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG,
-    [_COMPARE_OP_STR] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG,
+    [_COMPARE_OP_STR] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
     [_IS_OP] = HAS_ARG_FLAG,
     [_CONTAINS_OP] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
     [_CHECK_EG_MATCH] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
index 9d19b6c3ad3befbe2c0ce76b0448ee9374d3f5d7..3ba38c77710b2b35898e5b2428a327be888478f0 100644 (file)
@@ -574,7 +574,7 @@ class TestUopsOptimization(unittest.TestCase):
     def test_int_type_propagation(self):
         def testfunc(loops):
             num = 0
-            while num < loops:
+            for i in range(loops):
                 x = num + num
                 a = x + 1
                 num += 1
@@ -593,7 +593,7 @@ class TestUopsOptimization(unittest.TestCase):
             return x + x
         def testfunc(loops):
             num = 0
-            while num < loops:
+            for i in range(loops):
                 x = num + num
                 a = double(x)
                 num += 1
@@ -617,7 +617,7 @@ class TestUopsOptimization(unittest.TestCase):
             return x + x
         def testfunc(loops):
             num = 0
-            while num < loops:
+            for i in range(loops):
                 a = double(num)
                 x = a + a
                 num += 1
@@ -821,6 +821,59 @@ class TestUopsOptimization(unittest.TestCase):
         # We'll also need to verify that propagation actually occurs.
         self.assertIn("_BINARY_OP_MULTIPLY_FLOAT", uops)
 
+    def test_compare_op_type_propagation_float(self):
+        def testfunc(n):
+            a = 1.0
+            for _ in range(n):
+                x = a == a
+                x = a == a
+                x = a == a
+                x = a == a
+            return x
+
+        res, ex = self._run_with_optimizer(testfunc, 32)
+        self.assertTrue(res)
+        self.assertIsNotNone(ex)
+        uops = {opname for opname, _, _ in ex}
+        guard_both_float_count = [opname for opname, _, _ in ex if opname == "_GUARD_BOTH_FLOAT"]
+        self.assertLessEqual(len(guard_both_float_count), 1)
+        self.assertIn("_COMPARE_OP_FLOAT", uops)
+
+    def test_compare_op_type_propagation_int(self):
+        def testfunc(n):
+            a = 1
+            for _ in range(n):
+                x = a == a
+                x = a == a
+                x = a == a
+                x = a == a
+            return x
+
+        res, ex = self._run_with_optimizer(testfunc, 32)
+        self.assertTrue(res)
+        self.assertIsNotNone(ex)
+        uops = {opname for opname, _, _ in ex}
+        guard_both_float_count = [opname for opname, _, _ in ex if opname == "_GUARD_BOTH_INT"]
+        self.assertLessEqual(len(guard_both_float_count), 1)
+        self.assertIn("_COMPARE_OP_INT", uops)
+
+    def test_compare_op_type_propagation_unicode(self):
+        def testfunc(n):
+            a = ""
+            for _ in range(n):
+                x = a == a
+                x = a == a
+                x = a == a
+                x = a == a
+            return x
+
+        res, ex = self._run_with_optimizer(testfunc, 32)
+        self.assertTrue(res)
+        self.assertIsNotNone(ex)
+        uops = {opname for opname, _, _ in ex}
+        guard_both_float_count = [opname for opname, _, _ in ex if opname == "_GUARD_BOTH_UNICODE"]
+        self.assertLessEqual(len(guard_both_float_count), 1)
+        self.assertIn("_COMPARE_OP_STR", uops)
 
 if __name__ == "__main__":
     unittest.main()
index 27c439b71fa9d91886755468adbfab4f30611d82..10bb1525fc180199085cf3e95bca7cc2e075be7b 100644 (file)
@@ -2200,9 +2200,16 @@ dummy_func(
 
         macro(COMPARE_OP) = _SPECIALIZE_COMPARE_OP + _COMPARE_OP;
 
-        inst(COMPARE_OP_FLOAT, (unused/1, left, right -- res)) {
-            DEOPT_IF(!PyFloat_CheckExact(left));
-            DEOPT_IF(!PyFloat_CheckExact(right));
+        macro(COMPARE_OP_FLOAT) =
+            _GUARD_BOTH_FLOAT + unused/1 + _COMPARE_OP_FLOAT;
+
+        macro(COMPARE_OP_INT) =
+            _GUARD_BOTH_INT + unused/1 + _COMPARE_OP_INT;
+
+        macro(COMPARE_OP_STR) =
+            _GUARD_BOTH_UNICODE + unused/1 + _COMPARE_OP_STR;
+
+        op(_COMPARE_OP_FLOAT, (left, right -- res)) {
             STAT_INC(COMPARE_OP, hit);
             double dleft = PyFloat_AS_DOUBLE(left);
             double dright = PyFloat_AS_DOUBLE(right);
@@ -2215,9 +2222,7 @@ dummy_func(
         }
 
         // Similar to COMPARE_OP_FLOAT
-        inst(COMPARE_OP_INT, (unused/1, left, right -- res)) {
-            DEOPT_IF(!PyLong_CheckExact(left));
-            DEOPT_IF(!PyLong_CheckExact(right));
+        op(_COMPARE_OP_INT, (left, right -- res)) {
             DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left));
             DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right));
             STAT_INC(COMPARE_OP, hit);
@@ -2234,9 +2239,7 @@ dummy_func(
         }
 
         // Similar to COMPARE_OP_FLOAT, but for ==, != only
-        inst(COMPARE_OP_STR, (unused/1, left, right -- res)) {
-            DEOPT_IF(!PyUnicode_CheckExact(left));
-            DEOPT_IF(!PyUnicode_CheckExact(right));
+        op(_COMPARE_OP_STR, (left, right -- res)) {
             STAT_INC(COMPARE_OP, hit);
             int eq = _PyUnicode_Equal(left, right);
             assert((oparg >> 5) == Py_EQ || (oparg >> 5) == Py_NE);
index b46885e0d5cbc7001f5370b939dd44da90f87c66..445f98b469e9783191a2957d633d3df9e9dfaa42 100644 (file)
             oparg = CURRENT_OPARG();
             right = stack_pointer[-1];
             left = stack_pointer[-2];
-            if (!PyFloat_CheckExact(left)) goto deoptimize;
-            if (!PyFloat_CheckExact(right)) goto deoptimize;
             STAT_INC(COMPARE_OP, hit);
             double dleft = PyFloat_AS_DOUBLE(left);
             double dright = PyFloat_AS_DOUBLE(right);
             oparg = CURRENT_OPARG();
             right = stack_pointer[-1];
             left = stack_pointer[-2];
-            if (!PyLong_CheckExact(left)) goto deoptimize;
-            if (!PyLong_CheckExact(right)) goto deoptimize;
             if (!_PyLong_IsCompact((PyLongObject *)left)) goto deoptimize;
             if (!_PyLong_IsCompact((PyLongObject *)right)) goto deoptimize;
             STAT_INC(COMPARE_OP, hit);
             oparg = CURRENT_OPARG();
             right = stack_pointer[-1];
             left = stack_pointer[-2];
-            if (!PyUnicode_CheckExact(left)) goto deoptimize;
-            if (!PyUnicode_CheckExact(right)) goto deoptimize;
             STAT_INC(COMPARE_OP, hit);
             int eq = _PyUnicode_Equal(left, right);
             assert((oparg >> 5) == Py_EQ || (oparg >> 5) == Py_NE);
index 324e53dca63a8a0e07a93aa4ff1a0783f56e9e8c..78991066974df33f853d10bf13a6df5e059a7339 100644 (file)
             PyObject *right;
             PyObject *left;
             PyObject *res;
-            /* Skip 1 cache entry */
+            // _GUARD_BOTH_FLOAT
             right = stack_pointer[-1];
             left = stack_pointer[-2];
-            DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP);
-            DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP);
-            STAT_INC(COMPARE_OP, hit);
-            double dleft = PyFloat_AS_DOUBLE(left);
-            double dright = PyFloat_AS_DOUBLE(right);
-            // 1 if NaN, 2 if <, 4 if >, 8 if ==; this matches low four bits of the oparg
-            int sign_ish = COMPARISON_BIT(dleft, dright);
-            _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc);
-            _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);
-            res = (sign_ish & oparg) ? Py_True : Py_False;
-            // It's always a bool, so we don't care about oparg & 16.
+            {
+                DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP);
+                DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP);
+            }
+            /* Skip 1 cache entry */
+            // _COMPARE_OP_FLOAT
+            {
+                STAT_INC(COMPARE_OP, hit);
+                double dleft = PyFloat_AS_DOUBLE(left);
+                double dright = PyFloat_AS_DOUBLE(right);
+                // 1 if NaN, 2 if <, 4 if >, 8 if ==; this matches low four bits of the oparg
+                int sign_ish = COMPARISON_BIT(dleft, dright);
+                _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc);
+                _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);
+                res = (sign_ish & oparg) ? Py_True : Py_False;
+                // It's always a bool, so we don't care about oparg & 16.
+            }
             stack_pointer[-2] = res;
             stack_pointer += -1;
             DISPATCH();
             PyObject *right;
             PyObject *left;
             PyObject *res;
-            /* Skip 1 cache entry */
+            // _GUARD_BOTH_INT
             right = stack_pointer[-1];
             left = stack_pointer[-2];
-            DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP);
-            DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP);
-            DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP);
-            DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_OP);
-            STAT_INC(COMPARE_OP, hit);
-            assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 &&
+            {
+                DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP);
+                DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP);
+            }
+            /* Skip 1 cache entry */
+            // _COMPARE_OP_INT
+            {
+                DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP);
+                DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_OP);
+                STAT_INC(COMPARE_OP, hit);
+                assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 &&
                    _PyLong_DigitCount((PyLongObject *)right) <= 1);
-            Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left);
-            Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right);
-            // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg
-            int sign_ish = COMPARISON_BIT(ileft, iright);
-            _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
-            _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
-            res = (sign_ish & oparg) ? Py_True : Py_False;
-            // It's always a bool, so we don't care about oparg & 16.
+                Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left);
+                Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right);
+                // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg
+                int sign_ish = COMPARISON_BIT(ileft, iright);
+                _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
+                _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
+                res = (sign_ish & oparg) ? Py_True : Py_False;
+                // It's always a bool, so we don't care about oparg & 16.
+            }
             stack_pointer[-2] = res;
             stack_pointer += -1;
             DISPATCH();
             PyObject *right;
             PyObject *left;
             PyObject *res;
-            /* Skip 1 cache entry */
+            // _GUARD_BOTH_UNICODE
             right = stack_pointer[-1];
             left = stack_pointer[-2];
-            DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP);
-            DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP);
-            STAT_INC(COMPARE_OP, hit);
-            int eq = _PyUnicode_Equal(left, right);
-            assert((oparg >> 5) == Py_EQ || (oparg >> 5) == Py_NE);
-            _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc);
-            _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc);
-            assert(eq == 0 || eq == 1);
-            assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS);
-            assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS);
-            res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False;
-            // It's always a bool, so we don't care about oparg & 16.
+            {
+                DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP);
+                DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP);
+            }
+            /* Skip 1 cache entry */
+            // _COMPARE_OP_STR
+            {
+                STAT_INC(COMPARE_OP, hit);
+                int eq = _PyUnicode_Equal(left, right);
+                assert((oparg >> 5) == Py_EQ || (oparg >> 5) == Py_NE);
+                _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc);
+                _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc);
+                assert(eq == 0 || eq == 1);
+                assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS);
+                assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS);
+                res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False;
+                // It's always a bool, so we don't care about oparg & 16.
+            }
             stack_pointer[-2] = res;
             stack_pointer += -1;
             DISPATCH();
index 3f6e8ce1bbfbadd507c462098170d028546d4c85..e9b556d16c370253fcffe00b10c1eb397cab2745 100644 (file)
@@ -77,6 +77,14 @@ dummy_func(void) {
         sym_set_type(right, &PyFloat_Type);
     }
 
+    op(_GUARD_BOTH_UNICODE, (left, right -- left, right)) {
+        if (sym_matches_type(left, &PyUnicode_Type) &&
+            sym_matches_type(right, &PyUnicode_Type)) {
+            REPLACE_OP(this_instr, _NOP, 0 ,0);
+        }
+        sym_set_type(left, &PyUnicode_Type);
+        sym_set_type(right, &PyUnicode_Type);
+    }
 
     op(_BINARY_OP_ADD_INT, (left, right -- res)) {
         if (is_const(left) && is_const(right)) {
index 904700a0bbe64796ec021a2b634189660a08dd55..f41fe328195b4dc321b8a434d89033a6fcc55d45 100644 (file)
         }
 
         case _GUARD_BOTH_UNICODE: {
+            _Py_UOpsSymType *right;
+            _Py_UOpsSymType *left;
+            right = stack_pointer[-1];
+            left = stack_pointer[-2];
+            if (sym_matches_type(left, &PyUnicode_Type) &&
+                sym_matches_type(right, &PyUnicode_Type)) {
+                REPLACE_OP(this_instr, _NOP, 0 ,0);
+            }
+            sym_set_type(left, &PyUnicode_Type);
+            sym_set_type(right, &PyUnicode_Type);
             break;
         }