gh-146393: Optimize float division operations by mutating uniquely-referenced operands in place (JIT only) (GH-146397)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Pieter Eendebak 2026-04-14 20:08:04 +02:00 committed by GitHub
parent bdb0b36192
commit 95cbd4a232
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 1940 additions and 1263 deletions

View file

@ -289,7 +289,56 @@ dummy_func(void) {
bool rhs_int = sym_matches_type(rhs, &PyLong_Type);
bool lhs_float = sym_matches_type(lhs, &PyFloat_Type);
bool rhs_float = sym_matches_type(rhs, &PyFloat_Type);
if (!((lhs_int || lhs_float) && (rhs_int || rhs_float))) {
bool is_truediv = (oparg == NB_TRUE_DIVIDE
|| oparg == NB_INPLACE_TRUE_DIVIDE);
bool is_remainder = (oparg == NB_REMAINDER
|| oparg == NB_INPLACE_REMAINDER);
// Promote probable-float operands to known floats via speculative
// guards. _RECORD_TOS / _RECORD_NOS in the BINARY_OP macro record
// the observed operand during tracing, which sym_get_probable_type
// reads here. Applied only to ops where narrowing unlocks a
// meaningful downstream win:
// - NB_TRUE_DIVIDE: enables the specialized float path below.
// - NB_REMAINDER: lets the float result type propagate.
// NB_POWER is excluded — speculative guards there regressed
// test_power_type_depends_on_input_values (GH-127844).
if (is_truediv || is_remainder) {
if (!sym_has_type(rhs)
&& sym_get_probable_type(rhs) == &PyFloat_Type) {
ADD_OP(_GUARD_TOS_FLOAT, 0, 0);
sym_set_type(rhs, &PyFloat_Type);
rhs_float = true;
}
if (!sym_has_type(lhs)
&& sym_get_probable_type(lhs) == &PyFloat_Type) {
ADD_OP(_GUARD_NOS_FLOAT, 0, 0);
sym_set_type(lhs, &PyFloat_Type);
lhs_float = true;
}
}
if (is_truediv && lhs_float && rhs_float) {
if (PyJitRef_IsUnique(lhs)) {
ADD_OP(_BINARY_OP_TRUEDIV_FLOAT_INPLACE, 0, 0);
l = sym_new_null(ctx);
r = rhs;
}
else if (PyJitRef_IsUnique(rhs)) {
ADD_OP(_BINARY_OP_TRUEDIV_FLOAT_INPLACE_RIGHT, 0, 0);
l = lhs;
r = sym_new_null(ctx);
}
else {
ADD_OP(_BINARY_OP_TRUEDIV_FLOAT, 0, 0);
l = lhs;
r = rhs;
}
res = PyJitRef_MakeUnique(sym_new_type(ctx, &PyFloat_Type));
}
else if (is_truediv
&& (lhs_int || lhs_float) && (rhs_int || rhs_float)) {
res = PyJitRef_MakeUnique(sym_new_type(ctx, &PyFloat_Type));
}
else if (!((lhs_int || lhs_float) && (rhs_int || rhs_float))) {
// There's something other than an int or float involved:
res = sym_new_unknown(ctx);
}
@ -312,7 +361,7 @@ dummy_func(void) {
}
else if (lhs_float) {
// Case C:
res = sym_new_type(ctx, &PyFloat_Type);
res = PyJitRef_MakeUnique(sym_new_type(ctx, &PyFloat_Type));
}
else if (!sym_is_const(ctx, rhs)) {
// Case A or B... can't know without the sign of the RHS:
@ -320,21 +369,18 @@ dummy_func(void) {
}
else if (_PyLong_IsNegative((PyLongObject *)sym_get_const(ctx, rhs))) {
// Case B:
res = sym_new_type(ctx, &PyFloat_Type);
res = PyJitRef_MakeUnique(sym_new_type(ctx, &PyFloat_Type));
}
else {
// Case A:
res = sym_new_type(ctx, &PyLong_Type);
}
}
else if (oparg == NB_TRUE_DIVIDE || oparg == NB_INPLACE_TRUE_DIVIDE) {
res = sym_new_type(ctx, &PyFloat_Type);
}
else if (lhs_int && rhs_int) {
res = sym_new_type(ctx, &PyLong_Type);
}
else {
res = sym_new_type(ctx, &PyFloat_Type);
res = PyJitRef_MakeUnique(sym_new_type(ctx, &PyFloat_Type));
}
}