Skip to content

Commit a847067

Browse files
committed
[mypyc] feat: support non-sequence inputs with known len in sequence_from_generator_preallocate_helper
1 parent 5f4ef4d commit a847067

File tree

2 files changed

+136
-94
lines changed

2 files changed

+136
-94
lines changed

mypyc/irbuild/for_helpers.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -231,22 +231,41 @@ def sequence_from_generator_preallocate_helper(
231231
implementation.
232232
"""
233233
if len(gen.sequences) == 1 and len(gen.indices) == 1 and len(gen.condlists[0]) == 0:
234-
rtype = builder.node_type(gen.sequences[0])
234+
sequence_expr = gen.sequences[0]
235+
rtype = builder.node_type(sequence_expr)
235236
if is_sequence_rprimitive(rtype):
236-
sequence = builder.accept(gen.sequences[0])
237+
sequence = builder.accept(sequence_expr)
237238
length = get_expr_length_value(
238-
builder, gen.sequences[0], sequence, gen.line, use_pyssize_t=True
239+
builder, sequence_expr, sequence, gen.line, use_pyssize_t=True
239240
)
240241
target_op = empty_op_llbuilder(length, gen.line)
241242

242-
def set_item(item_index: Value) -> None:
243+
def set_item_index(item_index: Value) -> None:
243244
e = builder.accept(gen.left_expr)
244245
builder.call_c(set_item_op, [target_op, item_index, e], gen.line)
245246

246247
for_loop_helper_with_index(
247-
builder, gen.indices[0], gen.sequences[0], sequence, set_item, gen.line, length
248+
builder, gen.indices[0], sequence_expr, sequence, set_item_index, gen.line, length
248249
)
250+
return target_op
251+
252+
expr_length = get_expr_length(sequence_expr)
253+
if expr_length is not None:
254+
item_index = Register(int_rprimitive)
255+
builder.assign(item_index, Integer(0), gen.line)
249256

257+
def set_item_noindex() -> None:
258+
e = builder.accept(gen.left_expr)
259+
builder.call_c(set_item_op, [target_op, item_index, e], gen.line)
260+
builder.assign(
261+
item_index,
262+
builder.binary_op(item_index, Integer(1), "+", gen.line),
263+
gen.line,
264+
)
265+
266+
length = Integer(expr_length, c_pyssize_t_rprimitive, gen.line)
267+
target_op = empty_op_llbuilder(length, gen.line)
268+
for_loop_helper(builder, gen.indices[0], sequence_expr, set_item_noindex, None, False, gen.line, )
250269
return target_op
251270
return None
252271

mypyc/test-data/irbuild-tuple.test

Lines changed: 112 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,7 @@ def f(val: bool) -> bool:
837837

838838
def test() -> None:
839839
# this tuple is created from a very complex genexp but we can still compute the length and preallocate the tuple
840+
# r1 = PyTuple_New(5) the shorter input to the zip(...) has len 5
840841
a = tuple(
841842
x
842843
for x
@@ -852,101 +853,123 @@ L0:
852853
r0 = val ^ 1
853854
return r0
854855
def test():
855-
r0 :: list
856-
r1, r2, r3 :: object
857-
r4 :: object[1]
858-
r5 :: object_ptr
859-
r6 :: object
860-
r7 :: range
861-
r8 :: object
862-
r9 :: str
863-
r10 :: object
864-
r11 :: object[2]
865-
r12 :: object_ptr
866-
r13 :: object
867-
r14 :: str
868-
r15 :: tuple
869-
r16 :: object
870-
r17 :: str
871-
r18 :: object
872-
r19 :: object[1]
873-
r20 :: object_ptr
874-
r21 :: object
875-
r22 :: list
876-
r23 :: object
877-
r24 :: str
878-
r25 :: object
879-
r26 :: object[1]
880-
r27 :: object_ptr
881-
r28, r29 :: object
882-
r30 :: str
883-
r31 :: object
884-
r32 :: object[2]
885-
r33 :: object_ptr
886-
r34, r35, r36 :: object
887-
r37, x :: tuple[str, tuple[int, str]]
888-
r38 :: object
889-
r39 :: i32
890-
r40, r41 :: bit
891-
r42, a :: tuple
856+
r0 :: int
857+
r1 :: tuple
858+
r2, r3, r4 :: object
859+
r5 :: object[1]
860+
r6 :: object_ptr
861+
r7 :: object
862+
r8 :: range
863+
r9 :: object
864+
r10 :: str
865+
r11 :: object
866+
r12 :: object[2]
867+
r13 :: object_ptr
868+
r14 :: object
869+
r15 :: str
870+
r16 :: tuple
871+
r17 :: object
872+
r18 :: str
873+
r19 :: object
874+
r20 :: object[1]
875+
r21 :: object_ptr
876+
r22 :: object
877+
r23 :: list
878+
r24 :: object
879+
r25 :: str
880+
r26 :: object
881+
r27 :: object[1]
882+
r28 :: object_ptr
883+
r29, r30 :: object
884+
r31 :: str
885+
r32 :: object
886+
r33 :: object[2]
887+
r34 :: object_ptr
888+
r35, r36, r37 :: object
889+
r38, x :: tuple[str, tuple[int, str]]
890+
r39 :: native_int
891+
r40 :: bit
892+
r41, r42 :: native_int
893+
r43 :: ptr
894+
r44 :: c_ptr
895+
r45 :: i64
896+
r46 :: object
897+
r47 :: int
898+
r48 :: bit
899+
a :: tuple
892900
L0:
893-
r0 = PyList_New(0)
894-
r1 = load_address PyUnicode_Type
895-
r2 = load_address PyRange_Type
896-
r3 = object 5
897-
r4 = [r3]
898-
r5 = load_address r4
899-
r6 = PyObject_Vectorcall(r2, r5, 1, 0)
900-
keep_alive r3
901-
r7 = cast(range, r6)
902-
r8 = builtins :: module
903-
r9 = 'map'
904-
r10 = CPyObject_GetAttr(r8, r9)
905-
r11 = [r1, r7]
906-
r12 = load_address r11
907-
r13 = PyObject_Vectorcall(r10, r12, 2, 0)
908-
keep_alive r1, r7
909-
r14 = 'abcdefg'
910-
r15 = PySequence_Tuple(r14)
911-
r16 = builtins :: module
912-
r17 = 'reversed'
913-
r18 = CPyObject_GetAttr(r16, r17)
914-
r19 = [r15]
915-
r20 = load_address r19
916-
r21 = PyObject_Vectorcall(r18, r20, 1, 0)
917-
keep_alive r15
918-
r22 = CPySequence_Sort(r21)
919-
r23 = builtins :: module
920-
r24 = 'enumerate'
921-
r25 = CPyObject_GetAttr(r23, r24)
922-
r26 = [r22]
923-
r27 = load_address r26
924-
r28 = PyObject_Vectorcall(r25, r27, 1, 0)
925-
keep_alive r22
926-
r29 = builtins :: module
927-
r30 = 'zip'
928-
r31 = CPyObject_GetAttr(r29, r30)
929-
r32 = [r13, r28]
930-
r33 = load_address r32
931-
r34 = PyObject_Vectorcall(r31, r33, 2, 0)
932-
keep_alive r13, r28
933-
r35 = PyObject_GetIter(r34)
901+
r0 = 0
902+
r1 = PyTuple_New(5)
903+
r2 = load_address PyUnicode_Type
904+
r3 = load_address PyRange_Type
905+
r4 = object 5
906+
r5 = [r4]
907+
r6 = load_address r5
908+
r7 = PyObject_Vectorcall(r3, r6, 1, 0)
909+
keep_alive r4
910+
r8 = cast(range, r7)
911+
r9 = builtins :: module
912+
r10 = 'map'
913+
r11 = CPyObject_GetAttr(r9, r10)
914+
r12 = [r2, r8]
915+
r13 = load_address r12
916+
r14 = PyObject_Vectorcall(r11, r13, 2, 0)
917+
keep_alive r2, r8
918+
r15 = 'abcdefg'
919+
r16 = PySequence_Tuple(r15)
920+
r17 = builtins :: module
921+
r18 = 'reversed'
922+
r19 = CPyObject_GetAttr(r17, r18)
923+
r20 = [r16]
924+
r21 = load_address r20
925+
r22 = PyObject_Vectorcall(r19, r21, 1, 0)
926+
keep_alive r16
927+
r23 = CPySequence_Sort(r22)
928+
r24 = builtins :: module
929+
r25 = 'enumerate'
930+
r26 = CPyObject_GetAttr(r24, r25)
931+
r27 = [r23]
932+
r28 = load_address r27
933+
r29 = PyObject_Vectorcall(r26, r28, 1, 0)
934+
keep_alive r23
935+
r30 = builtins :: module
936+
r31 = 'zip'
937+
r32 = CPyObject_GetAttr(r30, r31)
938+
r33 = [r14, r29]
939+
r34 = load_address r33
940+
r35 = PyObject_Vectorcall(r32, r34, 2, 0)
941+
keep_alive r14, r29
942+
r36 = PyObject_GetIter(r35)
934943
L1:
935-
r36 = PyIter_Next(r35)
936-
if is_error(r36) goto L4 else goto L2
944+
r37 = PyIter_Next(r36)
945+
if is_error(r37) goto L7 else goto L2
937946
L2:
938-
r37 = unbox(tuple[str, tuple[int, str]], r36)
939-
x = r37
940-
r38 = box(tuple[str, tuple[int, str]], x)
941-
r39 = PyList_Append(r0, r38)
942-
r40 = r39 >= 0 :: signed
947+
r38 = unbox(tuple[str, tuple[int, str]], r37)
948+
x = r38
949+
r39 = r0 & 1
950+
r40 = r39 == 0
951+
if r40 goto L3 else goto L4 :: bool
943952
L3:
944-
goto L1
953+
r41 = r0 >> 1
954+
r42 = r41
955+
goto L5
945956
L4:
946-
r41 = CPy_NoErrOccurred()
957+
r43 = r0 ^ 1
958+
r44 = r43
959+
r45 = CPyLong_AsInt64(r44)
960+
r42 = r45
961+
keep_alive r0
947962
L5:
948-
r42 = PyList_AsTuple(r0)
949-
a = r42
963+
r46 = box(tuple[str, tuple[int, str]], x)
964+
CPySequenceTuple_SetItemUnsafe(r1, r42, r46)
965+
r47 = CPyTagged_Add(r0, 2)
966+
r0 = r47
967+
L6:
968+
goto L1
969+
L7:
970+
r48 = CPy_NoErrOccurred()
971+
L8:
972+
a = r1
950973
return 1
951974

952975
[case testTupleBuiltFromStars]

0 commit comments

Comments
 (0)