Skip to main content

Python/ceval.c (part 20)

Source:

cpython 3.14 @ ab2d84fe1023/Python/ceval.c

This annotation covers comparison and conditional jump specializations. See python_ceval19_detail for binary operator specializations.

Map

LinesSymbolRole
1-80COMPARE_OP_INTint < int direct comparison without tp_richcompare
81-160COMPARE_OP_FLOATfloat < float direct ob_fval comparison
161-260COMPARE_OP_STRstr == str using interned-pointer shortcut
261-380IS_OP / CONTAINS_OPIdentity check; in operator dispatch
381-500POP_JUMP_IF_NONE / POP_JUMP_IF_NOT_NONENone-check branch without boolean coercion

Reading

COMPARE_OP_INT

// CPython: Python/ceval.c:2720 COMPARE_OP_INT
inst(COMPARE_OP_INT, (left, right -- res)) {
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);
Py_ssize_t lv = _PyLong_CompactValue((PyLongObject *)left);
Py_ssize_t rv = _PyLong_CompactValue((PyLongObject *)right);
int sign = (lv > rv) - (lv < rv);
res = PyBool_FromLong(COMPARISON_TRUTH(oparg, sign));
DECREMENT_ADAPTIVE_COUNTER(this_instr[-1].cache);
}

COMPARISON_TRUTH maps the oparg comparison code (LT, LE, EQ, NE, GT, GE) to a boolean using the sign (-1, 0, 1). This avoids calling long_richcompare and the full tp_richcompare dispatch. Only works for compact integers.

COMPARE_OP_STR

// CPython: Python/ceval.c:2820 COMPARE_OP_STR
inst(COMPARE_OP_STR, (left, right -- res)) {
DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP);
DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP);
int eq;
if (left == right) {
eq = 1; /* Interned strings: identity implies equality */
} else {
eq = (PyUnicode_Compare(left, right) == 0);
}
/* Only EQ and NE are supported in this specialization */
DEOPT_IF(oparg != Py_EQ && oparg != Py_NE, COMPARE_OP);
res = (eq ^ (oparg == Py_NE)) ? Py_True : Py_False;
Py_INCREF(res);
}

String equality is the most common comparison in dict lookups and match statements. The pointer identity check (left == right) is a fast path for interned strings.

IS_OP

// CPython: Python/ceval.c:2900 IS_OP
inst(IS_OP, (left, right -- b)) {
int res = Py_Is(left, right) ^ oparg;
/* oparg=0: 'is', oparg=1: 'is not' */
b = res ? Py_True : Py_False;
Py_INCREF(b);
DECREF_INPUTS();
}

x is y compiles to IS_OP with oparg=0; x is not y uses oparg=1. The XOR with oparg flips the result for is not. Py_Is is a pointer comparison.

POP_JUMP_IF_NONE

// CPython: Python/ceval.c:2980 POP_JUMP_IF_NONE
inst(POP_JUMP_IF_NONE, (val --)) {
if (!Py_IsNone(val)) {
JUMPBY(oparg);
}
Py_DECREF(val);
}

if x is None: ... compiles to LOAD_FAST x + POP_JUMP_IF_NOT_NONE target. The specialized opcode avoids the overhead of PyObject_IsTrue (which would call __bool__ for non-trivial types) by checking val == &_Py_NoneStruct directly.

gopy notes

COMPARE_OP_INT is vm.CompareOpInt in vm/eval_specialize.go. COMPARE_OP_STR checks pointer equality first, then uses objects.UnicodeCompare. IS_OP calls objects.Is. POP_JUMP_IF_NONE uses objects.IsNone which checks identity against the singleton objects.None.