Skip to main content

Python/ceval.c (part 53)

Source:

cpython 3.14 @ ab2d84fe1023/Python/ceval.c

This annotation covers COMPARE_OP specializations for integer, float, and string comparison. See python_ceval52_detail for BINARY_OP specializations.

Map

LinesSymbolRole
1-80COMPARE_OP_INTInteger comparison specialization
81-160COMPARE_OP_FLOATFloat comparison specialization
161-240COMPARE_OP_STRString equality specialization
241-320IS_OP / CONTAINS_OPIdentity and membership tests
321-500COMPARE_OP (generic)Fallback slot dispatch

Reading

COMPARE_OP_INT

// CPython: Python/ceval.c:4840 COMPARE_OP_INT
inst(COMPARE_OP_INT, (unused/2, left, right -- res)) {
DEOPT_IF(!PyLong_CheckExact(left) || !PyLong_CheckExact(right));
/* Fast path for compact integers (single-digit) */
DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left) ||
!_PyLong_IsCompact((PyLongObject *)right));
Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left);
Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right);
int sign = (ileft > iright) - (ileft < iright);
res = PyBool_FromLong(compare_masks[oparg & 0xF] & (sign + 1));
DECREF_INPUTS();
DISPATCH();
}

The comparison result is computed as a sign (-1, 0, or +1) and then tested against a bitmask indexed by the comparison operator. This avoids a branch chain for <, <=, ==, >=, >, !=.

COMPARE_OP_FLOAT

// CPython: Python/ceval.c:4900 COMPARE_OP_FLOAT
inst(COMPARE_OP_FLOAT, (unused/2, left, right -- res)) {
DEOPT_IF(!PyFloat_CheckExact(left) || !PyFloat_CheckExact(right));
double dleft = PyFloat_AS_DOUBLE(left);
double dright = PyFloat_AS_DOUBLE(right);
int sign = (dleft > dright) - (dleft < dright);
res = PyBool_FromLong(compare_masks[oparg & 0xF] & (sign + 1));
DECREF_INPUTS();
DISPATCH();
}

Direct double comparison using C relational operators. NaN handling: (NaN > x) is false and (NaN < x) is false, so sign = 0, and 0 == 0 is true but NaN != NaN is true. The bitmask covers this correctly.

COMPARE_OP_STR

// CPython: Python/ceval.c:4960 COMPARE_OP_STR
inst(COMPARE_OP_STR, (unused/2, left, right -- res)) {
DEOPT_IF(!PyUnicode_CheckExact(left) || !PyUnicode_CheckExact(right));
/* Only specializes '==' and '!=' */
DEOPT_IF((oparg & 0xF) != Py_EQ && (oparg & 0xF) != Py_NE);
int eq = _PyUnicode_Equal(left, right);
res = PyBool_FromLong((oparg & 0xF) == Py_EQ ? eq : !eq);
DECREF_INPUTS();
DISPATCH();
}

_PyUnicode_Equal checks pointer identity first (interned strings compare equal instantly), then falls back to length + memcmp.

gopy notes

COMPARE_OP_INT is in vm/eval_simple.go. For compact integers, it reads PyLong.CompactValue() and uses a bitmask table. COMPARE_OP_FLOAT reads objects.Float.Value and uses the same bitmask. COMPARE_OP_STR checks pointer equality first via objects.Is, then strings.Equal.