Skip to content

Commit ff96b81

Browse files
gh-115480: Type propagate _BINARY_OP_ADD_UNICODE (GH-115710)
1 parent b5949ea commit ff96b81

File tree

3 files changed

+66
-8
lines changed

3 files changed

+66
-8
lines changed

Lib/test/test_capi/test_opt.py

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -795,11 +795,14 @@ def test_float_add_constant_propagation(self):
795795
def testfunc(n):
796796
a = 1.0
797797
for _ in range(n):
798-
a = a + 0.1
798+
a = a + 0.25
799+
a = a + 0.25
800+
a = a + 0.25
801+
a = a + 0.25
799802
return a
800803

801804
res, ex = self._run_with_optimizer(testfunc, 32)
802-
self.assertAlmostEqual(res, 4.2)
805+
self.assertAlmostEqual(res, 33.0)
803806
self.assertIsNotNone(ex)
804807
uops = get_opnames(ex)
805808
guard_both_float_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_FLOAT"]
@@ -812,11 +815,14 @@ def test_float_subtract_constant_propagation(self):
812815
def testfunc(n):
813816
a = 1.0
814817
for _ in range(n):
815-
a = a - 0.1
818+
a = a - 0.25
819+
a = a - 0.25
820+
a = a - 0.25
821+
a = a - 0.25
816822
return a
817823

818824
res, ex = self._run_with_optimizer(testfunc, 32)
819-
self.assertAlmostEqual(res, -2.2)
825+
self.assertAlmostEqual(res, -31.0)
820826
self.assertIsNotNone(ex)
821827
uops = get_opnames(ex)
822828
guard_both_float_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_FLOAT"]
@@ -829,11 +835,14 @@ def test_float_multiply_constant_propagation(self):
829835
def testfunc(n):
830836
a = 1.0
831837
for _ in range(n):
832-
a = a * 2.0
838+
a = a * 1.0
839+
a = a * 1.0
840+
a = a * 1.0
841+
a = a * 1.0
833842
return a
834843

835844
res, ex = self._run_with_optimizer(testfunc, 32)
836-
self.assertAlmostEqual(res, 2 ** 32)
845+
self.assertAlmostEqual(res, 1.0)
837846
self.assertIsNotNone(ex)
838847
uops = get_opnames(ex)
839848
guard_both_float_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_FLOAT"]
@@ -842,6 +851,24 @@ def testfunc(n):
842851
# We'll also need to verify that propagation actually occurs.
843852
self.assertIn("_BINARY_OP_MULTIPLY_FLOAT", uops)
844853

854+
def test_add_unicode_propagation(self):
855+
def testfunc(n):
856+
a = ""
857+
for _ in range(n):
858+
a + a
859+
a + a
860+
a + a
861+
a + a
862+
return a
863+
864+
res, ex = self._run_with_optimizer(testfunc, 32)
865+
self.assertEqual(res, "")
866+
self.assertIsNotNone(ex)
867+
uops = get_opnames(ex)
868+
guard_both_unicode_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_UNICODE"]
869+
self.assertLessEqual(len(guard_both_unicode_count), 1)
870+
self.assertIn("_BINARY_OP_ADD_UNICODE", uops)
871+
845872
def test_compare_op_type_propagation_float(self):
846873
def testfunc(n):
847874
a = 1.0

Python/optimizer_bytecodes.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,22 @@ dummy_func(void) {
254254
}
255255
}
256256

257+
op(_BINARY_OP_ADD_UNICODE, (left, right -- res)) {
258+
if (sym_is_const(left) && sym_is_const(right) &&
259+
sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) {
260+
PyObject *temp = PyUnicode_Concat(sym_get_const(left), sym_get_const(right));
261+
if (temp == NULL) {
262+
goto error;
263+
}
264+
res = sym_new_const(ctx, temp);
265+
Py_DECREF(temp);
266+
OUT_OF_SPACE_IF_NULL(res);
267+
}
268+
else {
269+
OUT_OF_SPACE_IF_NULL(res = sym_new_type(ctx, &PyUnicode_Type));
270+
}
271+
}
272+
257273
op(_TO_BOOL, (value -- res)) {
258274
(void)value;
259275
res = sym_new_type(ctx, &PyBool_Type);

Python/optimizer_cases.c.h

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

0 commit comments

Comments
 (0)