Skip to content

Commit b1f5121

Browse files
authored
[mypyc] Merge more primitive ops (#9110)
Relates to mypyc/mypyc#734. This PR completes ALL ops of dict, str, list, tuple, set that are supported using current design. The remaining ones would rather need to split into multiple ops (via specializers) or using pointers.
1 parent ffdbeb3 commit b1f5121

22 files changed

+325
-332
lines changed

mypyc/codegen/emit.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
is_float_rprimitive, is_bool_rprimitive, is_int_rprimitive, is_short_int_rprimitive,
1414
is_list_rprimitive, is_dict_rprimitive, is_set_rprimitive, is_tuple_rprimitive,
1515
is_none_rprimitive, is_object_rprimitive, object_rprimitive, is_str_rprimitive,
16-
int_rprimitive, is_optional_type, optional_value_type
16+
int_rprimitive, is_optional_type, optional_value_type, is_int32_rprimitive, is_int64_rprimitive
1717
)
1818
from mypyc.ir.func_ir import FuncDecl
1919
from mypyc.ir.class_ir import ClassIR, all_concrete_classes
@@ -695,6 +695,11 @@ def emit_box(self, src: str, dest: str, typ: RType, declare_dest: bool = False,
695695
self.emit_lines('{}{} = Py_None;'.format(declaration, dest))
696696
if not can_borrow:
697697
self.emit_inc_ref(dest, object_rprimitive)
698+
# TODO: This is a hack to handle mypy's false negative on unreachable code.
699+
# All ops returning int32/int64 should not be coerced into object.
700+
# Since their result will not be used elsewhere, it's safe to use NULL here
701+
elif is_int32_rprimitive(typ) or is_int64_rprimitive(typ):
702+
self.emit_lines('{}{} = NULL;'.format(declaration, dest))
698703
elif isinstance(typ, RTuple):
699704
self.declare_tuple_struct(typ)
700705
self.emit_line('{}{} = PyTuple_New({});'.format(declaration, dest, len(typ.types)))

mypyc/irbuild/builder.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ def add_to_non_ext_dict(self, non_ext: NonExtClassInfo,
245245
key: str, val: Value, line: int) -> None:
246246
# Add an attribute entry into the class dict of a non-extension class.
247247
key_unicode = self.load_static_unicode(key)
248-
self.primitive_op(dict_set_item_op, [non_ext.dict, key_unicode, val], line)
248+
self.call_c(dict_set_item_op, [non_ext.dict, key_unicode, val], line)
249249

250250
def gen_import(self, id: str, line: int) -> None:
251251
self.imports[id] = None
@@ -884,7 +884,7 @@ def load_global(self, expr: NameExpr) -> Value:
884884
def load_global_str(self, name: str, line: int) -> Value:
885885
_globals = self.load_globals_dict()
886886
reg = self.load_static_unicode(name)
887-
return self.primitive_op(dict_get_item_op, [_globals, reg], line)
887+
return self.call_c(dict_get_item_op, [_globals, reg], line)
888888

889889
def load_globals_dict(self) -> Value:
890890
return self.add(LoadStatic(dict_rprimitive, 'globals', self.module_name))

mypyc/irbuild/classdef.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,12 @@ def transform_class_def(builder: IRBuilder, cdef: ClassDef) -> None:
149149
builder.add(InitStatic(non_ext_class, cdef.name, builder.module_name, NAMESPACE_TYPE))
150150

151151
# Add the non-extension class to the dict
152-
builder.primitive_op(dict_set_item_op,
153-
[
154-
builder.load_globals_dict(),
155-
builder.load_static_unicode(cdef.name),
156-
non_ext_class
157-
], cdef.line)
152+
builder.call_c(dict_set_item_op,
153+
[
154+
builder.load_globals_dict(),
155+
builder.load_static_unicode(cdef.name),
156+
non_ext_class
157+
], cdef.line)
158158

159159
# Cache any cachable class attributes
160160
cache_class_attrs(builder, attrs_to_cache, cdef)
@@ -191,12 +191,12 @@ def allocate_class(builder: IRBuilder, cdef: ClassDef) -> Value:
191191
builder.add(InitStatic(tp, cdef.name, builder.module_name, NAMESPACE_TYPE))
192192

193193
# Add it to the dict
194-
builder.primitive_op(dict_set_item_op,
195-
[
196-
builder.load_globals_dict(),
197-
builder.load_static_unicode(cdef.name),
198-
tp,
199-
], cdef.line)
194+
builder.call_c(dict_set_item_op,
195+
[
196+
builder.load_globals_dict(),
197+
builder.load_static_unicode(cdef.name),
198+
tp,
199+
], cdef.line)
200200

201201
return tp
202202

@@ -280,7 +280,7 @@ def add_non_ext_class_attr(builder: IRBuilder,
280280
# TODO: Maybe generate more precise types for annotations
281281
key = builder.load_static_unicode(lvalue.name)
282282
typ = builder.primitive_op(type_object_op, [], stmt.line)
283-
builder.primitive_op(dict_set_item_op, [non_ext.anns, key, typ], stmt.line)
283+
builder.call_c(dict_set_item_op, [non_ext.anns, key, typ], stmt.line)
284284

285285
# Only add the attribute to the __dict__ if the assignment is of the form:
286286
# x: type = value (don't add attributes of the form 'x: type' to the __dict__).
@@ -470,9 +470,9 @@ def create_mypyc_attrs_tuple(builder: IRBuilder, ir: ClassIR, line: int) -> Valu
470470

471471
def finish_non_ext_dict(builder: IRBuilder, non_ext: NonExtClassInfo, line: int) -> None:
472472
# Add __annotations__ to the class dict.
473-
builder.primitive_op(dict_set_item_op,
474-
[non_ext.dict, builder.load_static_unicode('__annotations__'),
475-
non_ext.anns], -1)
473+
builder.call_c(dict_set_item_op,
474+
[non_ext.dict, builder.load_static_unicode('__annotations__'),
475+
non_ext.anns], -1)
476476

477477
# We add a __doc__ attribute so if the non-extension class is decorated with the
478478
# dataclass decorator, dataclass will not try to look for __text_signature__.

mypyc/irbuild/expression.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
)
2121
from mypyc.ir.rtypes import RTuple, object_rprimitive, is_none_rprimitive
2222
from mypyc.ir.func_ir import FUNC_CLASSMETHOD, FUNC_STATICMETHOD
23-
from mypyc.primitives.registry import name_ref_ops
23+
from mypyc.primitives.registry import name_ref_ops, CFunctionDescription
2424
from mypyc.primitives.generic_ops import iter_op
2525
from mypyc.primitives.misc_ops import new_slice_op, ellipsis_op, type_op
2626
from mypyc.primitives.list_ops import new_list_op, list_append_op, list_extend_op
@@ -491,8 +491,8 @@ def transform_set_expr(builder: IRBuilder, expr: SetExpr) -> Value:
491491
def _visit_display(builder: IRBuilder,
492492
items: List[Expression],
493493
constructor_op: OpDescription,
494-
append_op: OpDescription,
495-
extend_op: OpDescription,
494+
append_op: CFunctionDescription,
495+
extend_op: CFunctionDescription,
496496
line: int
497497
) -> Value:
498498
accepted_items = []
@@ -512,7 +512,7 @@ def _visit_display(builder: IRBuilder,
512512
if result is None:
513513
result = builder.primitive_op(constructor_op, initial_items, line)
514514

515-
builder.primitive_op(extend_op if starred else append_op, [result, value], line)
515+
builder.call_c(extend_op if starred else append_op, [result, value], line)
516516

517517
if result is None:
518518
result = builder.primitive_op(constructor_op, initial_items, line)
@@ -534,7 +534,7 @@ def transform_set_comprehension(builder: IRBuilder, o: SetComprehension) -> Valu
534534

535535
def gen_inner_stmts() -> None:
536536
e = builder.accept(gen.left_expr)
537-
builder.primitive_op(set_add_op, [set_ops, e], o.line)
537+
builder.call_c(set_add_op, [set_ops, e], o.line)
538538

539539
comprehension_helper(builder, loop_params, gen_inner_stmts, o.line)
540540
return set_ops
@@ -547,7 +547,7 @@ def transform_dictionary_comprehension(builder: IRBuilder, o: DictionaryComprehe
547547
def gen_inner_stmts() -> None:
548548
k = builder.accept(o.key)
549549
v = builder.accept(o.value)
550-
builder.primitive_op(dict_set_item_op, [d, k, v], o.line)
550+
builder.call_c(dict_set_item_op, [d, k, v], o.line)
551551

552552
comprehension_helper(builder, loop_params, gen_inner_stmts, o.line)
553553
return d

mypyc/irbuild/for_helpers.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@
1313
)
1414
from mypyc.ir.ops import (
1515
Value, BasicBlock, LoadInt, Branch, Register, AssignmentTarget, TupleGet,
16-
AssignmentTargetTuple, TupleSet, OpDescription, BinaryIntOp
16+
AssignmentTargetTuple, TupleSet, BinaryIntOp
1717
)
1818
from mypyc.ir.rtypes import (
1919
RType, is_short_int_rprimitive, is_list_rprimitive, is_sequence_rprimitive,
2020
RTuple, is_dict_rprimitive, short_int_rprimitive
2121
)
22+
from mypyc.primitives.registry import CFunctionDescription
2223
from mypyc.primitives.dict_ops import (
2324
dict_next_key_op, dict_next_value_op, dict_next_item_op, dict_check_size_op,
2425
dict_key_iter_op, dict_value_iter_op, dict_item_iter_op
@@ -92,7 +93,7 @@ def translate_list_comprehension(builder: IRBuilder, gen: GeneratorExpr) -> Valu
9293

9394
def gen_inner_stmts() -> None:
9495
e = builder.accept(gen.left_expr)
95-
builder.primitive_op(list_append_op, [list_ops, e], gen.line)
96+
builder.call_c(list_append_op, [list_ops, e], gen.line)
9697

9798
comprehension_helper(builder, loop_params, gen_inner_stmts, gen.line)
9899
return list_ops
@@ -485,8 +486,8 @@ class ForDictionaryCommon(ForGenerator):
485486
since they may override some iteration methods in subtly incompatible manner.
486487
The fallback logic is implemented in CPy.h via dynamic type check.
487488
"""
488-
dict_next_op = None # type: ClassVar[OpDescription]
489-
dict_iter_op = None # type: ClassVar[OpDescription]
489+
dict_next_op = None # type: ClassVar[CFunctionDescription]
490+
dict_iter_op = None # type: ClassVar[CFunctionDescription]
490491

491492
def need_cleanup(self) -> bool:
492493
# Technically, a dict subclass can raise an unrelated exception
@@ -504,14 +505,14 @@ def init(self, expr_reg: Value, target_type: RType) -> None:
504505
self.size = builder.maybe_spill(self.load_len(self.expr_target))
505506

506507
# For dict class (not a subclass) this is the dictionary itself.
507-
iter_reg = builder.primitive_op(self.dict_iter_op, [expr_reg], self.line)
508+
iter_reg = builder.call_c(self.dict_iter_op, [expr_reg], self.line)
508509
self.iter_target = builder.maybe_spill(iter_reg)
509510

510511
def gen_condition(self) -> None:
511512
"""Get next key/value pair, set new offset, and check if we should continue."""
512513
builder = self.builder
513514
line = self.line
514-
self.next_tuple = self.builder.primitive_op(
515+
self.next_tuple = self.builder.call_c(
515516
self.dict_next_op, [builder.read(self.iter_target, line),
516517
builder.read(self.offset_target, line)], line)
517518

@@ -532,9 +533,9 @@ def gen_step(self) -> None:
532533
builder = self.builder
533534
line = self.line
534535
# Technically, we don't need a new primitive for this, but it is simpler.
535-
builder.primitive_op(dict_check_size_op,
536-
[builder.read(self.expr_target, line),
537-
builder.read(self.size, line)], line)
536+
builder.call_c(dict_check_size_op,
537+
[builder.read(self.expr_target, line),
538+
builder.read(self.size, line)], line)
538539

539540
def gen_cleanup(self) -> None:
540541
# Same as for generic ForIterable.

mypyc/irbuild/function.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,10 @@ def transform_decorator(builder: IRBuilder, dec: Decorator) -> None:
9393
decorated_func = load_decorated_func(builder, dec.func, orig_func)
9494

9595
# Set the callable object representing the decorated function as a global.
96-
builder.primitive_op(dict_set_item_op,
97-
[builder.load_globals_dict(),
98-
builder.load_static_unicode(dec.func.name), decorated_func],
99-
decorated_func.line)
96+
builder.call_c(dict_set_item_op,
97+
[builder.load_globals_dict(),
98+
builder.load_static_unicode(dec.func.name), decorated_func],
99+
decorated_func.line)
100100

101101
builder.functions.append(func_ir)
102102

mypyc/irbuild/ll_builder.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ def py_call(self,
269269
# don't have an extend method.
270270
pos_args_list = self.primitive_op(new_list_op, pos_arg_values, line)
271271
for star_arg_value in star_arg_values:
272-
self.primitive_op(list_extend_op, [pos_args_list, star_arg_value], line)
272+
self.call_c(list_extend_op, [pos_args_list, star_arg_value], line)
273273
pos_args_tuple = self.call_c(list_tuple_op, [pos_args_list], line)
274274

275275
kw_args_dict = self.make_dict(kw_arg_key_value_pairs, line)
@@ -591,7 +591,7 @@ def make_dict(self, key_value_pairs: Sequence[DictEntry], line: int) -> Value:
591591
if result is None:
592592
result = self._create_dict(keys, values, line)
593593

594-
self.primitive_op(
594+
self.call_c(
595595
dict_update_in_display_op,
596596
[result, value],
597597
line=line

mypyc/irbuild/specialize.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,11 @@ def dict_methods_fast_path(
9999
# Note that it is not safe to use fast methods on dict subclasses, so
100100
# the corresponding helpers in CPy.h fallback to (inlined) generic logic.
101101
if attr == 'keys':
102-
return builder.primitive_op(dict_keys_op, [obj], expr.line)
102+
return builder.call_c(dict_keys_op, [obj], expr.line)
103103
elif attr == 'values':
104-
return builder.primitive_op(dict_values_op, [obj], expr.line)
104+
return builder.call_c(dict_values_op, [obj], expr.line)
105105
else:
106-
return builder.primitive_op(dict_items_op, [obj], expr.line)
106+
return builder.call_c(dict_items_op, [obj], expr.line)
107107

108108

109109
@specialize_function('builtins.tuple')

mypyc/irbuild/statement.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ def transform_import(builder: IRBuilder, node: Import) -> None:
126126

127127
# Python 3.7 has a nice 'PyImport_GetModule' function that we can't use :(
128128
mod_dict = builder.primitive_op(get_module_dict_op, [], node.line)
129-
obj = builder.primitive_op(dict_get_item_op,
130-
[mod_dict, builder.load_static_unicode(base)], node.line)
129+
obj = builder.call_c(dict_get_item_op,
130+
[mod_dict, builder.load_static_unicode(base)], node.line)
131131
builder.gen_method_call(
132132
globals, '__setitem__', [builder.load_static_unicode(name), obj],
133133
result_type=None, line=node.line)

0 commit comments

Comments
 (0)