Skip to content

Commit fb41108

Browse files
[mypyc] feat: stararg fastpath when calling fn(*args) with tuple (#19623)
There are 3 safe cases where we can reuse a tuple when calling a python function: fn(*args) fn(*args, **kwargs) fn(*args, k=1, k2=2, **kwargs) This PR covers the first two cases. The IR diff will probably demonstrate this change better than I can explain it.
1 parent b3d5021 commit fb41108

File tree

2 files changed

+37
-36
lines changed

2 files changed

+37
-36
lines changed

mypyc/irbuild/ll_builder.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,18 @@ def _construct_varargs(
789789
for value, kind, name in args:
790790
if kind == ARG_STAR:
791791
if star_result is None:
792+
# fast path if star expr is a tuple:
793+
# we can pass the immutable tuple straight into the function call.
794+
if is_tuple_rprimitive(value.type):
795+
if len(args) == 1:
796+
# fn(*args)
797+
return value, self._create_dict([], [], line)
798+
elif len(args) == 2 and args[1][1] == ARG_STAR2:
799+
# fn(*args, **kwargs)
800+
star_result = value
801+
continue
802+
# elif ...: TODO extend this to optimize fn(*args, k=1, **kwargs) case
803+
# TODO optimize this case using the length utils - currently in review
792804
star_result = self.new_list_op(star_values, line)
793805
self.primitive_op(list_extend_op, [star_result, value], line)
794806
elif kind == ARG_STAR2:
@@ -886,9 +898,11 @@ def _construct_varargs(
886898
# tuple. Otherwise create the tuple from the list.
887899
if star_result is None:
888900
star_result = self.new_tuple(star_values, line)
889-
else:
901+
elif not is_tuple_rprimitive(star_result.type):
902+
# if star_result is a tuple we took the fast path
890903
star_result = self.primitive_op(list_tuple_op, [star_result], line)
891904
if has_star2 and star2_result is None:
905+
# TODO: use dict_copy_op for simple cases of **kwargs
892906
star2_result = self._create_dict(star2_keys, star2_values, line)
893907

894908
return star_result, star2_result

mypyc/test-data/irbuild-generics.test

Lines changed: 22 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -166,25 +166,18 @@ execute(f, 1)
166166
def execute(func, args, kwargs):
167167
func :: object
168168
args :: tuple
169-
kwargs :: dict
170-
r0 :: list
171-
r1 :: object
172-
r2 :: dict
173-
r3 :: i32
174-
r4 :: bit
175-
r5 :: tuple
176-
r6 :: object
177-
r7 :: int
169+
kwargs, r0 :: dict
170+
r1 :: i32
171+
r2 :: bit
172+
r3 :: object
173+
r4 :: int
178174
L0:
179-
r0 = PyList_New(0)
180-
r1 = CPyList_Extend(r0, args)
181-
r2 = PyDict_New()
182-
r3 = CPyDict_UpdateInDisplay(r2, kwargs)
183-
r4 = r3 >= 0 :: signed
184-
r5 = PyList_AsTuple(r0)
185-
r6 = PyObject_Call(func, r5, r2)
186-
r7 = unbox(int, r6)
187-
return r7
175+
r0 = PyDict_New()
176+
r1 = CPyDict_UpdateInDisplay(r0, kwargs)
177+
r2 = r1 >= 0 :: signed
178+
r3 = PyObject_Call(func, args, r0)
179+
r4 = unbox(int, r3)
180+
return r4
188181
def f(x):
189182
x :: int
190183
L0:
@@ -709,14 +702,11 @@ def inner_deco_obj.__call__(__mypyc_self__, args, kwargs):
709702
can_dictcomp :: dict
710703
r22, can_iter, r23, can_use_keys, r24, can_use_values :: list
711704
r25 :: object
712-
r26 :: list
713-
r27 :: object
714-
r28 :: dict
715-
r29 :: i32
716-
r30 :: bit
717-
r31 :: tuple
718-
r32 :: object
719-
r33 :: int
705+
r26 :: dict
706+
r27 :: i32
707+
r28 :: bit
708+
r29 :: object
709+
r30 :: int
720710
L0:
721711
r0 = __mypyc_self__.__mypyc_env__
722712
r1 = var_object_size args
@@ -768,15 +758,12 @@ L9:
768758
r24 = CPyDict_Values(kwargs)
769759
can_use_values = r24
770760
r25 = r0.func
771-
r26 = PyList_New(0)
772-
r27 = CPyList_Extend(r26, args)
773-
r28 = PyDict_New()
774-
r29 = CPyDict_UpdateInDisplay(r28, kwargs)
775-
r30 = r29 >= 0 :: signed
776-
r31 = PyList_AsTuple(r26)
777-
r32 = PyObject_Call(r25, r31, r28)
778-
r33 = unbox(int, r32)
779-
return r33
761+
r26 = PyDict_New()
762+
r27 = CPyDict_UpdateInDisplay(r26, kwargs)
763+
r28 = r27 >= 0 :: signed
764+
r29 = PyObject_Call(r25, args, r26)
765+
r30 = unbox(int, r29)
766+
return r30
780767
def deco(func):
781768
func :: object
782769
r0 :: __main__.deco_env

0 commit comments

Comments
 (0)