8000 [mypyc] Implement new-style builtins.len for all supported types (#9284) · python/mypy@88eb84e · GitHub
[go: up one dir, main page]

Skip to content

Commit 88eb84e

Browse files
authored
[mypyc] Implement new-style builtins.len for all supported types (#9284)
This PR completes the support of the new style builtins.len for dict, set, tuple and generic cases.
1 parent 5e96821 commit 88eb84e

14 files changed

+316
-331
lines changed

mypyc/ir/rtypes.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,3 +681,21 @@ def is_optional_type(rtype: RType) -> bool:
681681
name='PyVarObject',
682682
names=['ob_base', 'ob_size'],
683683
types=[PyObject, c_pyssize_t_rprimitive])
684+
685+
setentry = RStruct(
686+
name='setentry',
687+
names=['key', 'hash'],
688+
types=[pointer_rprimitive, c_pyssize_t_rprimitive])
689+
690+
smalltable = RStruct(
691+
name='smalltable',
692+
names=[],
693+
types=[setentry] * 8)
694+
695+
PySetObject = RStruct(
696+
name='PySetObject',
697+
names=['ob_base', 'fill', 'used', 'mask', 'table', 'hash', 'finger',
698+
'smalltable', 'weakreflist'],
699+
types=[PyObject, c_pyssize_t_rprimitive, c_pyssize_t_rprimitive, c_pyssize_t_rprimitive,
700+
pointer_rprimitive, c_pyssize_t_rprimitive, c_pyssize_t_rprimitive, smalltable,
701+
pointer_rprimitive])

mypyc/irbuild/builder.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,8 @@ def binary_int_op(self, type: RType, lhs: Value, rhs: Value, op: int, line: int)
238238
def compare_tagged(self, lhs: Value, rhs: Value, op: str, line: int) -> Value:
239239
return self.builder.compare_tagged(lhs, rhs, op, line)
240240

241-
def list_len(self, val: Value, line: int) -> Value:
242-
return self.builder.list_len(val, line)
241+
def builtin_len(self, val: Value, line: int) -> Value:
242+
return self.builder.builtin_len(val, line)
243243

244244
@property
245245
def environment(self) -> Environment:
@@ -511,7 +511,7 @@ def process_iterator_tuple_assignment(self,
511511
if target.star_idx is not None:
512512
post_star_vals = target.items[split_idx + 1:]
513513
iter_list = self.call_c(to_list, [iterator], line)
514-
iter_list_len = self.list_len(iter_list, line)
514+
iter_list_len = self.builtin_len(iter_list, line)
515515
post_star_len = self.add(LoadInt(len(post_star_vals)))
516516
condition = self.binary_op(post_star_len, iter_list_len, '<=', line)
517517

mypyc/irbuild/for_helpers.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -332,14 +332,7 @@ def gen_cleanup(self) -> None:
332332

333333
def load_len(self, expr: Union[Value, AssignmentTarget]) -> Value:
334334
"""A helper to get collection length, used by several subclasses."""
335-
val = self.builder.read(expr, self.line)
336-
if is_list_rprimitive(val.type):
337-
return self.builder.builder.list_len(self.builder.read(expr, self.line), self.line)
338-
return self.builder.builder.builtin_call(
339-
[self.builder.read(expr, self.line)],
340-
'builtins.len',
341-
self.line,
342-
)
335+
return self.builder.builder.builtin_len(self.builder.read(expr, self.line), self.line)
343336

344337

345338
class ForIterable(ForGenerator):

mypyc/irbuild/ll_builder.py

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
from mypyc.ir.rtypes import (
2828
RType, RUnion, RInstance, optional_value_type, int_rprimitive, float_rprimitive,
2929
bool_rprimitive, list_rprimitive, str_rprimitive, is_none_rprimitive, object_rprimitive,
30-
c_pyssize_t_rprimitive, is_short_int_rprimitive, is_tagged, PyVarObject, short_int_rprimitive
30+
c_pyssize_t_rprimitive, is_short_int_rprimitive, is_tagged, PyVarObject, short_int_rprimitive,
31+
is_list_rprimitive, is_tuple_rprimitive, is_dict_rprimitive, is_set_rprimitive, PySetObject
3132
)
3233
from mypyc.ir.func_ir import FuncDecl, FuncSignature
3334
from mypyc.ir.class_ir import ClassIR, all_concrete_classes
@@ -45,10 +46,10 @@
4546
)
4647
from mypyc.primitives.tuple_ops import list_tuple_op, new_tuple_op
4748
from mypyc.primitives.dict_ops import (
48-
dict_update_in_display_op, dict_new_op, dict_build_op
49+
dict_update_in_display_op, dict_new_op, dict_build_op, dict_size_op
4950
)
5051
from mypyc.primitives.generic_ops import (
51-
py_getattr_op, py_call_op, py_call_with_kwargs_op, py_method_call_op
52+
py_getattr_op, py_call_op, py_call_with_kwargs_op, py_method_call_op, generic_len_op
5253
)
5354
from mypyc.primitives.misc_ops import (
5455
none_op, none_object_op, false_op, fast_isinstance_op, bool_op, type_is_op
@@ -704,7 +705,7 @@ def add_bool_branch(self, value: Value, true: BasicBlock, false: BasicBlock) ->
704705
zero = self.add(LoadInt(0))
705706
value = self.binary_op(value, zero, '!=', value.line)
706707
elif is_same_type(value.type, list_rprimitive):
707-
length = self.list_len(value, value.line)
708+
length = self.builtin_len(value, value.line)
708709
zero = self.add(LoadInt(0))
709710
value = self.binary_op(length, zero, '!=', value.line)
710711
elif (isinstance(value.type, RInstance) and value.type.class_ir.is_ext_class
@@ -811,12 +812,29 @@ def matching_call_c(self,
811812
def binary_int_op(self, type: RType, lhs: Value, rhs: Value, op: int, line: int) -> Value:
812813
return self.add(BinaryIntOp(type, lhs, rhs, op, line))
813814

814-
def list_len(self, val: Value, line: int) -> Value:
815-
elem_address = self.add(GetElementPtr(val, PyVarObject, 'ob_size'))
816-
size_value = self.add(LoadMem(c_pyssize_t_rprimitive, elem_address))
817-
offset = self.add(LoadInt(1, -1, rtype=c_pyssize_t_rprimitive))
818-
return self.binary_int_op(short_int_rprimitive, size_value, offset,
819-
BinaryIntOp.LEFT_SHIFT, -1)
815+
def builtin_len(self, val: Value, line: int) -> Value:
816+
typ = val.type
817+
if is_list_rprimitive(typ) or is_tuple_rprimitive(typ):
818+
elem_address = self.add(GetElementPtr(val, PyVarObject, 'ob_size'))
819+
size_value = self.add(LoadMem(c_pyssize_t_rprimitive, elem_address))
820+
offset = self.add(LoadInt(1, line, rtype=c_pyssize_t_rprimitive))
821+
return self.binary_int_op(short_int_rprimitive, size_value, offset,
822+
BinaryIntOp.LEFT_SHIFT, line)
823+
elif is_dict_rprimitive(typ):
824+
size_value = self.call_c(dict_size_op, [val], line)
825+
offset = self.add(LoadInt(1, line, rtype=c_pyssize_t_rprimitive))
826+
return self.binary_int_op(short_int_rprimitive, size_value, offset,
827+
BinaryIntOp.LEFT_SHIFT, line)
828+
elif is_set_rprimitive(typ):
829+
elem_address = self.add(GetElementPtr(val, PySetObject, 'used'))
830+
size_value = self.add(LoadMem(c_pyssize_t_rprimitive, elem_address))
831+
offset = self.add(LoadInt(1, line, rtype=c_pyssize_t_rprimitive))
832+
return self.binary_int_op(short_int_rprimitive, size_value, offset,
833+
BinaryIntOp.LEFT_SHIFT, line)
834+
# generic case
835+
else:
836+
return self.call_c(generic_len_op, [val], line)
837+
820838
# Internal helpers
821839

822840
def decompose_union_helper(self,

mypyc/irbuild/specialize.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
)
2323
from mypyc.ir.rtypes import (
2424
RType, RTuple, str_rprimitive, list_rprimitive, dict_rprimitive, set_rprimitive,
25-
bool_rprimitive, is_dict_rprimitive, is_list_rprimitive,
25+
bool_rprimitive, is_dict_rprimitive
2626
)
2727
from mypyc.primitives.dict_ops import dict_keys_op, dict_values_op, dict_items_op
2828
from mypyc.primitives.misc_ops import true_op, false_op
@@ -75,9 +75,9 @@ def translate_len(
7575
# though we still need to evaluate it.
7676
builder.accept(expr.args[0])
7777
return builder.add(LoadInt(len(expr_rtype.types)))
78-
elif is_list_rprimitive(expr_rtype):
78+
else:
7979
obj = builder.accept(expr.args[0])
80-
return builder.list_len(obj, -1)
80+
return builder.builtin_len(obj, -1)
8181
return None
8282

8383

mypyc/primitives/dict_ops.py

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
"""Primitive dict ops."""
22

3-
from typing import List
4-
5-
from mypyc.ir.ops import EmitterInterface, ERR_FALSE, ERR_MAGIC, ERR_NEVER, ERR_NEG_INT
3+
from mypyc.ir.ops import ERR_FALSE, ERR_MAGIC, ERR_NEVER, ERR_NEG_INT
64
from mypyc.ir.rtypes import (
75
dict_rprimitive, object_rprimitive, bool_rprimitive, int_rprimitive,
86
list_rprimitive, dict_next_rtuple_single, dict_next_rtuple_pair, c_pyssize_t_rprimitive,
97
c_int_rprimitive
108
)
119

1210
from mypyc.primitives.registry import (
13-
name_ref_op, method_op, func_op,
11+
name_ref_op, method_op,
1412
simple_emit, name_emit, c_custom_op, c_method_op, c_function_op, c_binary_op
1513
)
1614

@@ -168,21 +166,6 @@
168166
c_function_name='CPyDict_Items',
169167
error_kind=ERR_MAGIC)
170168

171-
172-
def emit_len(emitter: EmitterInterface, args: List[str], dest: str) -> None:
173-
temp = emitter.temp_name()
174-
emitter.emit_declaration('Py_ssize_t %s;' % temp)
175-
emitter.emit_line('%s = PyDict_Size(%s);' % (temp, args[0]))
176-
emitter.emit_line('%s = CPyTagged_ShortFromSsize_t(%s);' % (dest, temp))
177-
178-
179-
# len(dict)
180-
func_op(name='builtins.len',
181-
arg_types=[dict_rprimitive],
182-
result_type=int_rprimitive,
183-
error_kind=ERR_NEVER,
184-
emit=emit_len)
185-
186169
# PyDict_Next() fast iteration
187170
dict_key_iter_op = c_custom_op(
188171
arg_types=[dict_rprimitive],
@@ -226,3 +209,9 @@ def emit_len(emitter: EmitterInterface, args: List[str], dest: str) -> None:
226209
return_type=bool_rprimitive,
227210
c_function_name='CPyDict_CheckSize',
228211
error_kind=ERR_FALSE)
212+
213+
dict_size_op = c_custom_op(
214+
arg_types=[dict_rprimitive],
215+
return_type=c_pyssize_t_rprimitive,
216+
c_function_name='PyDict_Size',
217+
error_kind=ERR_NEVER)

mypyc/primitives/generic_ops.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from mypyc.ir.ops import ERR_NEVER, ERR_MAGIC, ERR_NEG_INT
1313
from mypyc.ir.rtypes import object_rprimitive, int_rprimitive, bool_rprimitive, c_int_rprimitive
1414
from mypyc.primitives.registry import (
15-
binary_op, unary_op, func_op, custom_op, call_emit, simple_emit,
15+
binary_op, unary_op, custom_op, call_emit, simple_emit,
1616
call_negative_magic_emit, negative_int_emit,
1717
c_binary_op, c_unary_op, c_method_op, c_function_op, c_custom_op
1818
)
@@ -226,12 +226,11 @@
226226
emit=simple_emit('{dest} = CPyObject_CallMethodObjArgs({comma_args}, NULL);'))
227227

228228
# len(obj)
229-
func_op(name='builtins.len',
230-
arg_types=[object_rprimitive],
231-
result_type=int_rprimitive,
232-
error_kind=ERR_NEVER,
233-
emit=call_emit('CPyObject_Size'),
234-
priority=0)
229+
generic_len_op = c_custom_op(
230+
arg_types=[object_rprimitive],
231+
return_type=int_rprimitive,
232+
c_function_name='CPyObject_Size',
233+
error_kind=ERR_NEVER)
235234

236235
# iter(obj)
237236
iter_op = c_function_op(name='builtins.iter',

mypyc/primitives/set_ops.py

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
from mypyc.primitives.registry import (
44
func_op, simple_emit, c_function_op, c_method_op, c_binary_op
55
)
6-
from mypyc.ir.ops import ERR_MAGIC, ERR_FALSE, ERR_NEVER, ERR_NEG_INT, EmitterInterface
6+
from mypyc.ir.ops import ERR_MAGIC, ERR_FALSE, ERR_NEG_INT
77
from mypyc.ir.rtypes import (
8-
object_rprimitive, bool_rprimitive, set_rprimitive, int_rprimitive, c_int_rprimitive
8+
object_rprimitive, bool_rprimitive, set_rprimitive, c_int_rprimitive
99
)
10-
from typing import List
1110

1211

1312
# Construct an empty set.
@@ -35,23 +34,6 @@
3534
c_function_name='PyFrozenSet_New',
3635
error_kind=ERR_MAGIC)
3736

38-
39-
def emit_len(emitter: EmitterInterface, args: List[str], dest: str) -> None:
40-
temp = emitter.temp_name()
41-
emitter.emit_declaration('Py_ssize_t %s;' % temp)
42-
emitter.emit_line('%s = PySet_GET_SIZE(%s);' % (temp, args[0]))
43-
emitter.emit_line('%s = CPyTagged_ShortFromSsize_t(%s);' % (dest, temp))
44-
45-
46-
# len(set)
47-
func_op(
48-
name='builtins.len',
49-
arg_types=[set_rprimitive],
50-
result_type=int_rprimitive,
51-
error_kind=ERR_NEVER,
52-
emit=emit_len,
53-
)
54-
5537
# item in set
5638
c_binary_op(
5739
name='in',

mypyc/primitives/tuple_ops.py

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,10 @@
44
objects, i.e. tuple_rprimitive (RPrimitive), not RTuple.
55
"""
66

7-
from typing import List
8-
9-
from mypyc.ir.ops import (
10-
EmitterInterface, ERR_NEVER, ERR_MAGIC
11-
)
7+
from mypyc.ir.ops import ERR_MAGIC
128
from mypyc.ir.rtypes import tuple_rprimitive, int_rprimitive, list_rprimitive, object_rprimitive
139
from mypyc.primitives.registry import (
14-
func_op, c_method_op, custom_op, simple_emit, c_function_op
10+
c_method_op, custom_op, simple_emit, c_function_op
1511
)
1612

1713

@@ -33,22 +29,6 @@
3329
format_str='{dest} = ({comma_args}) :: tuple',
3430
emit=simple_emit('{dest} = PyTuple_Pack({num_args}{comma_if_args}{comma_args});'))
3531

36-
37-
def emit_len(emitter: EmitterInterface, args: List[str], dest: str) -> None:
38-
temp = emitter.temp_name()
39-
emitter.emit_declaration('Py_ssize_t %s;' % temp)
40-
emitter.emit_line('%s = PyTuple_GET_SIZE(%s);' % (temp, args[0]))
41-
emitter.emit_line('%s = CPyTagged_ShortFromSsize_t(%s);' % (dest, temp))
42-
43-
44-
# len(tuple)
45-
tuple_len_op = func_op(
46-
name='builtins.len',
47-
arg_types=[tuple_rprimitive],
48-
result_type=int_rprimitive,
49-
error_kind=ERR_NEVER,
50-
emit=emit_len)
51-
5232
# Construct tuple from a list.
5333
list_tuple_op = c_function_op(
5434
name='builtins.tuple',

0 commit comments

Comments
 (0)
0