Skip to content

[mypyc] Speed up and improve multiple assignment #9800

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Dec 29, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Minor optimization, more comments, improve test case
  • Loading branch information
JukkaL committed Dec 12, 2020
commit 237111bb610bb32db5f34a23d6cc84493b819646
22 changes: 18 additions & 4 deletions mypyc/irbuild/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
from mypyc.ir.func_ir import FuncIR, INVALID_FUNC_DEF
from mypyc.ir.class_ir import ClassIR, NonExtClassInfo
from mypyc.primitives.registry import CFunctionDescription, function_ops
from mypyc.primitives.list_ops import to_list, list_pop_last
from mypyc.primitives.list_ops import to_list, list_pop_last, list_get_item_unsafe_op
from mypyc.primitives.dict_ops import dict_get_item_op, dict_set_item_op
from mypyc.primitives.generic_ops import py_setattr_op, iter_op, next_op
from mypyc.primitives.misc_ops import import_op, check_unpack_count_op
Expand Down Expand Up @@ -505,15 +505,29 @@ def process_sequence_assignment(self,
target: AssignmentTargetTuple,
rvalue: Value,
line: int) -> None:
"""Process assignment like 'x, y = s', where s is a variable-length list or tuple."""
# Check the length of sequence.
expected_len = self.add(LoadInt(len(target.items), rtype=c_pyssize_t_rprimitive))
self.builder.call_c(check_unpack_count_op, [rvalue, expected_len], line)
# Read values from the sequence and assign them to the targets.
# If some lvalue item is not a register, we conservatively
# assume that the length of the sequence might change due to a
# property setter or custom __setitem__.
simple_lvalue = all(isinstance(item, AssignmentTargetRegister)
for item in target.items)
# If it's possible for the length of the rvalue to change
# between item assignments, we must do it the hard way to
# preserve semantics.
if not simple_lvalue and is_list_rprimitive(rvalue.type):
return self.process_iterator_tuple_assignment(target, rvalue, line)
# Get values and assign them to the target items.
for i in range(len(target.items)):
item = target.items[i]
index = self.builder.load_static_int(i)
item_value = self.builder.gen_method_call(
rvalue, '__getitem__', [index], item.type, line)
if is_list_rprimitive(rvalue.type):
item_value = self.call_c(list_get_item_unsafe_op, [rvalue, index], line)
else:
item_value = self.builder.gen_method_call(
rvalue, '__getitem__', [index], item.type, line)
self.assign(target.items[i], item_value, line)

def process_iterator_tuple_assignment_helper(self,
Expand Down
4 changes: 2 additions & 2 deletions mypyc/test-data/irbuild-statements.test
Original file line number Diff line number Diff line change
Expand Up @@ -624,9 +624,9 @@ def f(l, t):
L0:
r0 = CPySequence_CheckUnpackCount(l, 2)
r1 = r0 >= 0 :: signed
r2 = CPyList_GetItemShort(l, 0)
r2 = CPyList_GetItemUnsafe(l, 0)
x = r2
r3 = CPyList_GetItemShort(l, 2)
r3 = CPyList_GetItemUnsafe(l, 2)
r4 = unbox(int, r3)
y = r4
r5 = CPySequence_CheckUnpackCount(t, 2)
Expand Down
15 changes: 14 additions & 1 deletion mypyc/test-data/run-misc.test
Original file line number Diff line number Diff line change
Expand Up @@ -348,11 +348,16 @@ def from_list(l: List[int]) -> List[int]:
x, y = l
return [y, x]

def from_list_complex(l: List[int]) -> List[int]:
ll = l[:]
ll[1], ll[0] = l
return ll

def from_any(o: Any) -> List[Any]:
x, y = o
return [y, x]
[file driver.py]
from native import from_tuple, from_tuple_sequence, from_list, from_any
from native import from_tuple, from_tuple_sequence, from_list, from_list_complex, from_any

assert from_tuple((1, 'x')) == ['x', 1]

Expand All @@ -372,6 +377,14 @@ except ValueError as e:
else:
assert False

assert from_list_complex([7, 6]) == [6, 7]
try:
from_list_complex([5, 4, 3])
except ValueError as e:
assert 'too many values to unpack (expected 2)' in str(e)
else:
assert False

assert from_any('xy') == ['y', 'x']

[case testUnpack]
Expand Down