Skip to content

Commit 2833dd4

Browse files
committed
Don't bother with more complex cases
1 parent 222b2c8 commit 2833dd4

File tree

3 files changed

+78
-120
lines changed

3 files changed

+78
-120
lines changed

Lib/test/test_capi/test_opt.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,11 +1544,11 @@ def f(l: complex, r: complex) -> None:
15441544
interesting = [
15451545
(1, 1), # int ** int -> int
15461546
(1, -1), # int ** int -> float
1547-
(1, 1.0), # int ** float -> float
1548-
(-1, 0.1), # int ** float -> complex
15491547
(1.0, 1), # float ** int -> float
1548+
(1, 1.0), # int ** float -> float
1549+
(-1, 0.5), # int ** float -> complex
15501550
(1.0, 1.0), # float ** float -> float
1551-
(-1.0, 0.1), # float ** float -> complex
1551+
(-1.0, 0.5), # float ** float -> complex
15521552
]
15531553
for (l, r), (x, y) in itertools.product(interesting, repeat=2):
15541554
s = template.format(l=l, r=r, x=x, y=y)

Python/optimizer_bytecodes.c

Lines changed: 31 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -171,66 +171,43 @@ dummy_func(void) {
171171
bool rhs_int = sym_matches_type(right, &PyLong_Type);
172172
bool lhs_float = sym_matches_type(left, &PyFloat_Type);
173173
bool rhs_float = sym_matches_type(right, &PyFloat_Type);
174-
if ((!lhs_int && !lhs_float) || (!rhs_int && !rhs_float)) {
174+
if (!((lhs_int || lhs_float) && (rhs_int || rhs_float))) {
175+
// There's something other than an int or float involved:
175176
res = sym_new_unknown(ctx);
176-
goto binary_op_done;
177-
}
178-
if (oparg == NB_POWER || oparg == NB_INPLACE_POWER) {
179-
// This one's fun: the *type* of the result depends on the *values*
180-
// being exponentiated. But exponents with one constant part are
181-
// reasonably common, so it's probably worth trying to be precise:
182-
PyObject *lhs_const = sym_get_const(left);
183-
PyObject *rhs_const = sym_get_const(right);
184-
if (lhs_int && rhs_int) {
185-
if (rhs_const == NULL) {
186-
// Unknown RHS means either int or float:
187-
res = sym_new_unknown(ctx);
188-
goto binary_op_done;
189-
}
190-
if (!_PyLong_IsNegative((PyLongObject *)rhs_const)) {
191-
// Non-negative RHS means int:
192-
res = sym_new_type(ctx, &PyLong_Type);
193-
goto binary_op_done;
194-
}
195-
// Negative RHS uses float_pow...
177+
}
178+
else if (oparg == NB_POWER || oparg == NB_INPLACE_POWER) {
179+
// This one's fun... the *type* of the result depends on the
180+
// *values* being exponentiated. However, exponents with one
181+
// constant part are reasonably common, so it's probably worth
182+
// trying to infer some simple cases:
183+
// - A: 1 ** 1 -> 1 (int ** int -> int)
184+
// - B: 1 ** -1 -> 1.0 (int ** int -> float)
185+
// - C: 1.0 ** 1 -> 1.0 (float ** int -> float)
186+
// - D: 1 ** 1.0 -> 1.0 (int ** float -> float)
187+
// - E: -1 ** 0.5 ~> 1j (int ** float -> complex)
188+
// - F: 1.0 ** 1.0 -> 1.0 (float ** float -> float)
189+
// - G: -1.0 ** 0.5 ~> 1j (float ** float -> complex)
190+
if (rhs_float) {
191+
// Case D, E, F, or G... can't know without the sign of the LHS
192+
// or whether the RHS is whole, which isn't worth the effort:
193+
res = sym_new_unknown(ctx);
196194
}
197-
// Negative LHS *and* non-integral RHS means complex. So we need to
198-
// disprove at least one to prove a float result:
199-
if (rhs_int) {
200-
// Integral RHS means float:
195+
else if (lhs_float) {
196+
// Case C:
201197
res = sym_new_type(ctx, &PyFloat_Type);
202-
goto binary_op_done;
203198
}
204-
if (rhs_const) {
205-
double rhs_double = PyFloat_AS_DOUBLE(rhs_const);
206-
if (rhs_double == floor(rhs_double)) {
207-
// Integral RHS means float:
208-
res = sym_new_type(ctx, &PyFloat_Type);
209-
goto binary_op_done;
210-
}
199+
else if (!sym_is_const(right)) {
200+
// Case A or B... can't know without the sign of the RHS:
201+
res = sym_new_unknown(ctx);
211202
}
212-
if (lhs_const) {
213-
if (lhs_int) {
214-
if (!_PyLong_IsNegative((PyLongObject *)lhs_const)) {
215-
// Non-negative LHS means float:
216-
res = sym_new_type(ctx, &PyFloat_Type);
217-
goto binary_op_done;
218-
}
219-
}
220-
else if (0.0 <= PyFloat_AS_DOUBLE(lhs_const)) {
221-
// Non-negative LHS means float:
222-
res = sym_new_type(ctx, &PyFloat_Type);
223-
goto binary_op_done;
224-
}
225-
if (rhs_const) {
226-
// If we have two constants and failed to disprove that it's
227-
// complex, then it's complex:
228-
res = sym_new_type(ctx, &PyComplex_Type);
229-
goto binary_op_done;
230-
}
203+
else if (_PyLong_IsNegative((PyLongObject *)sym_get_const(right))) {
204+
// Case B:
205+
res = sym_new_type(ctx, &PyFloat_Type);
206+
}
207+
else {
208+
// Case A:
209+
res = sym_new_type(ctx, &PyLong_Type);
231210
}
232-
// Couldn't prove anything. It's either float or complex:
233-
res = sym_new_unknown(ctx);
234211
}
235212
else if (oparg == NB_TRUE_DIVIDE || oparg == NB_INPLACE_TRUE_DIVIDE) {
236213
res = sym_new_type(ctx, &PyFloat_Type);
@@ -241,7 +218,6 @@ dummy_func(void) {
241218
else {
242219
res = sym_new_type(ctx, &PyFloat_Type);
243220
}
244-
binary_op_done:
245221
}
246222

247223
op(_BINARY_OP_ADD_INT, (left, right -- res)) {

Python/optimizer_cases.c.h

Lines changed: 44 additions & 62 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)