Skip to content

Commit b8b217b

Browse files
committed
Add failing unit tests for str comparison
1 parent 57ee7f3 commit b8b217b

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

Lib/test/test_capi/test_opt.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,50 @@ def return_tenth():
978978
# Constant narrowing allows constant folding for second comparison
979979
self.assertLessEqual(count_ops(ex, "_COMPARE_OP_FLOAT"), 1)
980980

981+
def test_compare_str_eq_narrows_to_constant(self):
982+
def f(n):
983+
def return_hello():
984+
return "hello"
985+
986+
hits = 0
987+
v = return_hello()
988+
for _ in range(n):
989+
if v == "hello":
990+
if v == "hello":
991+
hits += 1
992+
return hits
993+
994+
res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
995+
self.assertEqual(res, TIER2_THRESHOLD)
996+
self.assertIsNotNone(ex)
997+
uops = get_opnames(ex)
998+
999+
# Constant narrowing allows constant folding for second comparison
1000+
self.assertLessEqual(count_ops(ex, "_COMPARE_OP_STR"), 1)
1001+
1002+
def test_compare_str_ne_narrows_to_constant(self):
1003+
def f(n):
1004+
def return_hello():
1005+
return "hello"
1006+
1007+
hits = 0
1008+
v = return_hello()
1009+
for _ in range(n):
1010+
if v != "hello":
1011+
hits += 1000
1012+
else:
1013+
if v == "hello":
1014+
hits += 1
1015+
return hits
1016+
1017+
res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
1018+
self.assertEqual(res, TIER2_THRESHOLD)
1019+
self.assertIsNotNone(ex)
1020+
uops = get_opnames(ex)
1021+
1022+
# Constant narrowing allows constant folding for second comparison
1023+
self.assertLessEqual(count_ops(ex, "_COMPARE_OP_STR"), 1)
1024+
9811025
@unittest.skip("gh-139109 WIP")
9821026
def test_combine_stack_space_checks_sequential(self):
9831027
def dummy12(x):

Python/optimizer_symbols.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,6 +1419,58 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
14191419
_Py_uop_sym_apply_predicate_narrowing(ctx, ref, true);
14201420
TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, subject), "predicate narrowing incorrectly narrowed subject (inverted/true)");
14211421

1422+
// Test narrowing subject to constant from EQ predicate for str
1423+
subject = _Py_uop_sym_new_unknown(ctx);
1424+
PyObject *str_hello_obj = PyUnicode_FromString("hello");
1425+
JitOptRef const_str_hello = _Py_uop_sym_new_const(ctx, str_hello_obj);
1426+
if (PyJitRef_IsNull(subject) || str_hello_obj == NULL || PyJitRef_IsNull(const_str_hello)) {
1427+
goto fail;
1428+
}
1429+
ref = _Py_uop_sym_new_predicate(ctx, subject, const_str_hello, JIT_PRED_EQ);
1430+
if (PyJitRef_IsNull(ref)) {
1431+
goto fail;
1432+
}
1433+
_Py_uop_sym_apply_predicate_narrowing(ctx, ref, true);
1434+
TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (str)");
1435+
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == str_hello_obj, "predicate narrowing did not narrow subject to hello");
1436+
1437+
// Resolving EQ predicate to False should not narrow subject for str
1438+
subject = _Py_uop_sym_new_unknown(ctx);
1439+
if (PyJitRef_IsNull(subject)) {
1440+
goto fail;
1441+
}
1442+
ref = _Py_uop_sym_new_predicate(ctx, subject, const_str_hello, JIT_PRED_EQ);
1443+
if (PyJitRef_IsNull(ref)) {
1444+
goto fail;
1445+
}
1446+
_Py_uop_sym_apply_predicate_narrowing(ctx, ref, false);
1447+
TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, subject), "predicate narrowing incorrectly narrowed subject (inverted/true)");
1448+
1449+
// Test narrowing subject to constant from NE predicate for str
1450+
subject = _Py_uop_sym_new_unknown(ctx);
1451+
if (PyJitRef_IsNull(subject)) {
1452+
goto fail;
1453+
}
1454+
ref = _Py_uop_sym_new_predicate(ctx, subject, const_str_hello, JIT_PRED_NE);
1455+
if (PyJitRef_IsNull(ref)) {
1456+
goto fail;
1457+
}
1458+
_Py_uop_sym_apply_predicate_narrowing(ctx, ref, false);
1459+
TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (str)");
1460+
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == str_hello_obj, "predicate narrowing did not narrow subject to hello");
1461+
1462+
// Resolving NE predicate to true should not narrow subject for str
1463+
subject = _Py_uop_sym_new_unknown(ctx);
1464+
if (PyJitRef_IsNull(subject)) {
1465+
goto fail;
1466+
}
1467+
ref = _Py_uop_sym_new_predicate(ctx, subject, const_str_hello, JIT_PRED_NE);
1468+
if (PyJitRef_IsNull(ref)) {
1469+
goto fail;
1470+
}
1471+
_Py_uop_sym_apply_predicate_narrowing(ctx, ref, true);
1472+
TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, subject), "predicate narrowing incorrectly narrowed subject (inverted/true)");
1473+
14221474
val_big = PyNumber_Lshift(_PyLong_GetOne(), PyLong_FromLong(66));
14231475
if (val_big == NULL) {
14241476
goto fail;

0 commit comments

Comments
 (0)