Skip to content

Commit 7a03b22

Browse files
committed
Add failing unit tests for float EQ, NE
1 parent 030bc28 commit 7a03b22

2 files changed

Lines changed: 102 additions & 7 deletions

File tree

Lib/test/test_capi/test_opt.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,49 @@ def return_1():
932932
# v + 1 should be constant folded
933933
self.assertLessEqual(count_ops(ex, "_BINARY_OP_ADD_INT"), 1)
934934

935+
def test_compare_float_eq_narrows_to_constant(self):
936+
def f(n):
937+
def return_tenth():
938+
return 0.1
939+
940+
hits = 0
941+
v = return_tenth()
942+
for _ in range(n):
943+
if v == 0.1:
944+
if v == 0.1:
945+
hits += 1
946+
return hits
947+
948+
res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
949+
self.assertEqual(res, TIER2_THRESHOLD)
950+
self.assertIsNotNone(ex)
951+
uops = get_opnames(ex)
952+
953+
self.assertLessEqual(count_ops(ex, "_COMPARE_OP_FLOAT"), 1)
954+
955+
956+
def test_compare_float_ne_narrows_to_constant(self):
957+
def f(n):
958+
def return_tenth():
959+
return 0.1
960+
961+
hits = 0
962+
v = return_tenth()
963+
for _ in range(n):
964+
if v != 0.1:
965+
hits += 1000
966+
else:
967+
if v == 0.1:
968+
hits += 1
969+
return hits
970+
971+
res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
972+
self.assertEqual(res, TIER2_THRESHOLD)
973+
self.assertIsNotNone(ex)
974+
uops = get_opnames(ex)
975+
976+
self.assertLessEqual(count_ops(ex, "_COMPARE_OP_FLOAT"), 1)
977+
935978
@unittest.skip("gh-139109 WIP")
936979
def test_combine_stack_space_checks_sequential(self):
937980
def dummy12(x):

Python/optimizer_symbols.c

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,7 +1306,7 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
13061306
subject = _Py_uop_sym_new_unknown(ctx);
13071307
PyObject *one_obj = PyLong_FromLong(1);
13081308
JitOptRef const_one = _Py_uop_sym_new_const(ctx, one_obj);
1309-
if (PyJitRef_IsNull(subject) || PyJitRef_IsNull(const_one)) {
1309+
if (PyJitRef_IsNull(subject) || one_obj == NULL || PyJitRef_IsNull(const_one)) {
13101310
goto fail;
13111311
}
13121312
ref = _Py_uop_sym_new_predicate(ctx, subject, const_one, JIT_PRED_IS);
@@ -1317,9 +1317,9 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
13171317
TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (1)");
13181318
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == one_obj, "predicate narrowing did not narrow subject to 1");
13191319

1320-
// Test narrowing subject to numerical constant from EQ predicate
1320+
// Test narrowing subject to constant from EQ predicate for int
13211321
subject = _Py_uop_sym_new_unknown(ctx);
1322-
if (PyJitRef_IsNull(subject) || PyJitRef_IsNull(const_one)) {
1322+
if (PyJitRef_IsNull(subject)) {
13231323
goto fail;
13241324
}
13251325
ref = _Py_uop_sym_new_predicate(ctx, subject, const_one, JIT_PRED_EQ);
@@ -1330,7 +1330,7 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
13301330
TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (1)");
13311331
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == one_obj, "predicate narrowing did not narrow subject to 1");
13321332

1333-
// Resolving EQ predicate to False should not narrow subject
1333+
// Resolving EQ predicate to False should not narrow subject for int
13341334
subject = _Py_uop_sym_new_unknown(ctx);
13351335
if (PyJitRef_IsNull(subject)) {
13361336
goto fail;
@@ -1342,9 +1342,9 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
13421342
_Py_uop_sym_apply_predicate_narrowing(ctx, ref, false);
13431343
TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, subject), "predicate narrowing incorrectly narrowed subject (inverted/true)");
13441344

1345-
// Test narrowing subject to numerical constant from NE predicate
1345+
// Test narrowing subject to constant from NE predicate for int
13461346
subject = _Py_uop_sym_new_unknown(ctx);
1347-
if (PyJitRef_IsNull(subject) || PyJitRef_IsNull(const_one)) {
1347+
if (PyJitRef_IsNull(subject)) {
13481348
goto fail;
13491349
}
13501350
ref = _Py_uop_sym_new_predicate(ctx, subject, const_one, JIT_PRED_NE);
@@ -1355,7 +1355,7 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
13551355
TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (1)");
13561356
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == one_obj, "predicate narrowing did not narrow subject to 1");
13571357

1358-
// Resolving NE predicate to true should not narrow subject
1358+
// Resolving NE predicate to true should not narrow subject for int
13591359
subject = _Py_uop_sym_new_unknown(ctx);
13601360
if (PyJitRef_IsNull(subject)) {
13611361
goto fail;
@@ -1367,6 +1367,58 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
13671367
_Py_uop_sym_apply_predicate_narrowing(ctx, ref, true);
13681368
TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, subject), "predicate narrowing incorrectly narrowed subject (inverted/true)");
13691369

1370+
// Test narrowing subject to constant from EQ predicate for float
1371+
subject = _Py_uop_sym_new_unknown(ctx);
1372+
PyObject *float_tenth_obj = PyFloat_FromDouble(0.1);
1373+
JitOptRef const_float_tenth = _Py_uop_sym_new_const(ctx, float_tenth_obj);
1374+
if (PyJitRef_IsNull(subject) || float_tenth_obj == NULL || PyJitRef_IsNull(const_float_tenth)) {
1375+
goto fail;
1376+
}
1377+
ref = _Py_uop_sym_new_predicate(ctx, subject, const_float_tenth, JIT_PRED_EQ);
1378+
if (PyJitRef_IsNull(ref)) {
1379+
goto fail;
1380+
}
1381+
_Py_uop_sym_apply_predicate_narrowing(ctx, ref, true);
1382+
TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (float)");
1383+
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == float_tenth_obj, "predicate narrowing did not narrow subject to 0.1");
1384+
1385+
// Resolving EQ predicate to False should not narrow subject for float
1386+
subject = _Py_uop_sym_new_unknown(ctx);
1387+
if (PyJitRef_IsNull(subject)) {
1388+
goto fail;
1389+
}
1390+
ref = _Py_uop_sym_new_predicate(ctx, subject, const_float_tenth, JIT_PRED_EQ);
1391+
if (PyJitRef_IsNull(ref)) {
1392+
goto fail;
1393+
}
1394+
_Py_uop_sym_apply_predicate_narrowing(ctx, ref, false);
1395+
TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, subject), "predicate narrowing incorrectly narrowed subject (inverted/true)");
1396+
1397+
// Test narrowing subject to constant from NE predicate for float
1398+
subject = _Py_uop_sym_new_unknown(ctx);
1399+
if (PyJitRef_IsNull(subject)) {
1400+
goto fail;
1401+
}
1402+
ref = _Py_uop_sym_new_predicate(ctx, subject, const_float_tenth, JIT_PRED_NE);
1403+
if (PyJitRef_IsNull(ref)) {
1404+
goto fail;
1405+
}
1406+
_Py_uop_sym_apply_predicate_narrowing(ctx, ref, false);
1407+
TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (float)");
1408+
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == float_tenth_obj, "predicate narrowing did not narrow subject to 0.1");
1409+
1410+
// Resolving NE predicate to true should not narrow subject for float
1411+
subject = _Py_uop_sym_new_unknown(ctx);
1412+
if (PyJitRef_IsNull(subject)) {
1413+
goto fail;
1414+
}
1415+
ref = _Py_uop_sym_new_predicate(ctx, subject, const_float_tenth, JIT_PRED_NE);
1416+
if (PyJitRef_IsNull(ref)) {
1417+
goto fail;
1418+
}
1419+
_Py_uop_sym_apply_predicate_narrowing(ctx, ref, true);
1420+
TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, subject), "predicate narrowing incorrectly narrowed subject (inverted/true)");
1421+
13701422
val_big = PyNumber_Lshift(_PyLong_GetOne(), PyLong_FromLong(66));
13711423
if (val_big == NULL) {
13721424
goto fail;

0 commit comments

Comments
 (0)