summaryrefslogtreecommitdiffstats
path: root/Python/optimizer_bytecodes.c
diff options
context:
space:
mode:
authorBrandt Bucher <brandtbucher@microsoft.com>2025-01-08 01:25:48 (GMT)
committerGitHub <noreply@github.com>2025-01-08 01:25:48 (GMT)
commit65ae3d5a73ca3c53a0c6b601dddb8e9b3b6e3f51 (patch)
tree08dc3c35f3163f6cf176bd5e4aa82519333b6ed8 /Python/optimizer_bytecodes.c
parente08b28235a863323ca3a7e444776bb7803e77caf (diff)
downloadcpython-65ae3d5a73ca3c53a0c6b601dddb8e9b3b6e3f51.zip
cpython-65ae3d5a73ca3c53a0c6b601dddb8e9b3b6e3f51.tar.gz
cpython-65ae3d5a73ca3c53a0c6b601dddb8e9b3b6e3f51.tar.bz2
GH-127809: Fix the JIT's understanding of ** (GH-127844)
Diffstat (limited to 'Python/optimizer_bytecodes.c')
-rw-r--r--Python/optimizer_bytecodes.c57
1 files changed, 45 insertions, 12 deletions
diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c
index a14d119..8639448 100644
--- a/Python/optimizer_bytecodes.c
+++ b/Python/optimizer_bytecodes.c
@@ -167,23 +167,56 @@ dummy_func(void) {
}
op(_BINARY_OP, (left, right -- res)) {
- PyTypeObject *ltype = sym_get_type(left);
- PyTypeObject *rtype = sym_get_type(right);
- if (ltype != NULL && (ltype == &PyLong_Type || ltype == &PyFloat_Type) &&
- rtype != NULL && (rtype == &PyLong_Type || rtype == &PyFloat_Type))
- {
- if (oparg != NB_TRUE_DIVIDE && oparg != NB_INPLACE_TRUE_DIVIDE &&
- ltype == &PyLong_Type && rtype == &PyLong_Type) {
- /* If both inputs are ints and the op is not division the result is an int */
- res = sym_new_type(ctx, &PyLong_Type);
+ bool lhs_int = sym_matches_type(left, &PyLong_Type);
+ bool rhs_int = sym_matches_type(right, &PyLong_Type);
+ bool lhs_float = sym_matches_type(left, &PyFloat_Type);
+ bool rhs_float = sym_matches_type(right, &PyFloat_Type);
+ if (!((lhs_int || lhs_float) && (rhs_int || rhs_float))) {
+ // There's something other than an int or float involved:
+ res = sym_new_unknown(ctx);
+ }
+ else if (oparg == NB_POWER || oparg == NB_INPLACE_POWER) {
+ // This one's fun... the *type* of the result depends on the
+ // *values* being exponentiated. However, exponents with one
+ // constant part are reasonably common, so it's probably worth
+ // trying to infer some simple cases:
+ // - A: 1 ** 1 -> 1 (int ** int -> int)
+ // - B: 1 ** -1 -> 1.0 (int ** int -> float)
+ // - C: 1.0 ** 1 -> 1.0 (float ** int -> float)
+ // - D: 1 ** 1.0 -> 1.0 (int ** float -> float)
+ // - E: -1 ** 0.5 ~> 1j (int ** float -> complex)
+ // - F: 1.0 ** 1.0 -> 1.0 (float ** float -> float)
+ // - G: -1.0 ** 0.5 ~> 1j (float ** float -> complex)
+ if (rhs_float) {
+ // Case D, E, F, or G... can't know without the sign of the LHS
+ // or whether the RHS is whole, which isn't worth the effort:
+ res = sym_new_unknown(ctx);
}
- else {
- /* For any other op combining ints/floats the result is a float */
+ else if (lhs_float) {
+ // Case C:
res = sym_new_type(ctx, &PyFloat_Type);
}
+ else if (!sym_is_const(right)) {
+ // Case A or B... can't know without the sign of the RHS:
+ res = sym_new_unknown(ctx);
+ }
+ else if (_PyLong_IsNegative((PyLongObject *)sym_get_const(right))) {
+ // Case B:
+ res = 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_unknown(ctx);
+ res = sym_new_type(ctx, &PyFloat_Type);
}
}