Skip to content

Commit ddd202a

Browse files
committed
Add constant narrowing for _COMPARE_OP_INT
1 parent de4c33f commit ddd202a

File tree

4 files changed

+84
-3
lines changed

4 files changed

+84
-3
lines changed

Include/internal/pycore_optimizer_types.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ typedef struct {
7676
typedef enum {
7777
JIT_PRED_IS,
7878
JIT_PRED_IS_NOT,
79+
JIT_PRED_EQ,
80+
JIT_PRED_NE,
7981
} JitOptPredicateKind;
8082

8183
typedef struct {

Python/optimizer_bytecodes.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,22 @@ dummy_func(void) {
514514
}
515515

516516
op(_COMPARE_OP_INT, (left, right -- res, l, r)) {
517-
res = sym_new_type(ctx, &PyBool_Type);
517+
/* Comparison oparg masks */
518+
const int COMPARE_LT_MASK = 2;
519+
const int COMPARE_GT_MASK = 4;
520+
const int COMPARE_EQ_MASK = 8;
521+
522+
int cmp_mask = oparg & (COMPARE_LT_MASK | COMPARE_GT_MASK | COMPARE_EQ_MASK);
523+
524+
if (cmp_mask == COMPARE_EQ_MASK) {
525+
res = sym_new_predicate(ctx, left, right, JIT_PRED_EQ);
526+
}
527+
else if (cmp_mask == (COMPARE_LT_MASK | COMPARE_GT_MASK)) {
528+
res = sym_new_predicate(ctx, left, right, JIT_PRED_NE);
529+
}
530+
else {
531+
res = sym_new_type(ctx, &PyBool_Type);
532+
}
518533
l = left;
519534
r = right;
520535
REPLACE_OPCODE_IF_EVALUATES_PURE(left, right, res);

Python/optimizer_cases.c.h

Lines changed: 13 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/optimizer_symbols.c

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -875,9 +875,11 @@ _Py_uop_sym_apply_predicate_narrowing(JitOptContext *ctx, JitOptRef ref, bool br
875875

876876
bool narrow = false;
877877
switch(pred.kind) {
878+
case JIT_PRED_EQ:
878879
case JIT_PRED_IS:
879880
narrow = branch_is_true;
880881
break;
882+
case JIT_PRED_NE:
881883
case JIT_PRED_IS_NOT:
882884
narrow = !branch_is_true;
883885
break;
@@ -1300,7 +1302,7 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
13001302
TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (None)");
13011303
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == Py_None, "predicate narrowing did not narrow subject to None");
13021304

1303-
// Test narrowing subject to numerical constant
1305+
// Test narrowing subject to numerical constant from is comparison
13041306
subject = _Py_uop_sym_new_unknown(ctx);
13051307
PyObject *one_obj = PyLong_FromLong(1);
13061308
JitOptRef const_one = _Py_uop_sym_new_const(ctx, one_obj);
@@ -1314,6 +1316,56 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
13141316
_Py_uop_sym_apply_predicate_narrowing(ctx, ref, true);
13151317
TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (1)");
13161318
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == one_obj, "predicate narrowing did not narrow subject to 1");
1319+
1320+
// Test narrowing subject to numerical constant from EQ predicate
1321+
subject = _Py_uop_sym_new_unknown(ctx);
1322+
if (PyJitRef_IsNull(subject) || PyJitRef_IsNull(const_one)) {
1323+
goto fail;
1324+
}
1325+
ref = _Py_uop_sym_new_predicate(ctx, subject, const_one, JIT_PRED_EQ);
1326+
if (PyJitRef_IsNull(ref)) {
1327+
goto fail;
1328+
}
1329+
_Py_uop_sym_apply_predicate_narrowing(ctx, ref, true);
1330+
TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (1)");
1331+
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == one_obj, "predicate narrowing did not narrow subject to 1");
1332+
1333+
// Resolving EQ predicate to False should not narrow subject
1334+
subject = _Py_uop_sym_new_unknown(ctx);
1335+
if (PyJitRef_IsNull(subject)) {
1336+
goto fail;
1337+
}
1338+
ref = _Py_uop_sym_new_predicate(ctx, subject, const_one, JIT_PRED_EQ);
1339+
if (PyJitRef_IsNull(ref)) {
1340+
goto fail;
1341+
}
1342+
_Py_uop_sym_apply_predicate_narrowing(ctx, ref, false);
1343+
TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, subject), "predicate narrowing incorrectly narrowed subject (inverted/true)");
1344+
1345+
// Test narrowing subject to numerical constant from NE predicate
1346+
subject = _Py_uop_sym_new_unknown(ctx);
1347+
if (PyJitRef_IsNull(subject) || PyJitRef_IsNull(const_one)) {
1348+
goto fail;
1349+
}
1350+
ref = _Py_uop_sym_new_predicate(ctx, subject, const_one, JIT_PRED_NE);
1351+
if (PyJitRef_IsNull(ref)) {
1352+
goto fail;
1353+
}
1354+
_Py_uop_sym_apply_predicate_narrowing(ctx, ref, false);
1355+
TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (1)");
1356+
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == one_obj, "predicate narrowing did not narrow subject to 1");
1357+
1358+
// Resolving NE predicate to true should not narrow subject
1359+
subject = _Py_uop_sym_new_unknown(ctx);
1360+
if (PyJitRef_IsNull(subject)) {
1361+
goto fail;
1362+
}
1363+
ref = _Py_uop_sym_new_predicate(ctx, subject, const_one, JIT_PRED_NE);
1364+
if (PyJitRef_IsNull(ref)) {
1365+
goto fail;
1366+
}
1367+
_Py_uop_sym_apply_predicate_narrowing(ctx, ref, true);
1368+
TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, subject), "predicate narrowing incorrectly narrowed subject (inverted/true)");
13171369

13181370
val_big = PyNumber_Lshift(_PyLong_GetOne(), PyLong_FromLong(66));
13191371
if (val_big == NULL) {

0 commit comments

Comments
 (0)