Skip to content

[mypyc] Merge more primitive ops #9110

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 8 commits into from
Jul 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
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
7 changes: 6 additions & 1 deletion mypyc/codegen/emit.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
is_float_rprimitive, is_bool_rprimitive, is_int_rprimitive, is_short_int_rprimitive,
is_list_rprimitive, is_dict_rprimitive, is_set_rprimitive, is_tuple_rprimitive,
is_none_rprimitive, is_object_rprimitive, object_rprimitive, is_str_rprimitive,
int_rprimitive, is_optional_type, optional_value_type
int_rprimitive, is_optional_type, optional_value_type, is_int32_rprimitive, is_int64_rprimitive
)
from mypyc.ir.func_ir import FuncDecl
from mypyc.ir.class_ir import ClassIR, all_concrete_classes
Expand Down Expand Up @@ -695,6 +695,11 @@ def emit_box(self, src: str, dest: str, typ: RType, declare_dest: bool = False,
self.emit_lines('{}{} = Py_None;'.format(declaration, dest))
if not can_borrow:
self.emit_inc_ref(dest, object_rprimitive)
# TODO: This is a hack to handle mypy's false negative on unreachable code.
# All ops returning int32/int64 should not be coerced into object.
# Since their result will not be used elsewhere, it's safe to use NULL here
elif is_int32_rprimitive(typ) or is_int64_rprimitive(typ):
self.emit_lines('{}{} = NULL;'.format(declaration, dest))
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here's the hack

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine for now, but can you create a follow-up issue to properly box these as Python int objects? It should be easy enough to support, and it could be useful in the future.

elif isinstance(typ, RTuple):
self.declare_tuple_struct(typ)
self.emit_line('{}{} = PyTuple_New({});'.format(declaration, dest, len(typ.types)))
Expand Down
4 changes: 2 additions & 2 deletions mypyc/irbuild/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ def add_to_non_ext_dict(self, non_ext: NonExtClassInfo,
key: str, val: Value, line: int) -> None:
# Add an attribute entry into the class dict of a non-extension class.
key_unicode = self.load_static_unicode(key)
self.primitive_op(dict_set_item_op, [non_ext.dict, key_unicode, val], line)
self.call_c(dict_set_item_op, [non_ext.dict, key_unicode, val], line)

def gen_import(self, id: str, line: int) -> None:
self.imports[id] = None
Expand Down Expand Up @@ -884,7 +884,7 @@ def load_global(self, expr: NameExpr) -> Value:
def load_global_str(self, name: str, line: int) -> Value:
_globals = self.load_globals_dict()
reg = self.load_static_unicode(name)
return self.primitive_op(dict_get_item_op, [_globals, reg], line)
return self.call_c(dict_get_item_op, [_globals, reg], line)

def load_globals_dict(self) -> Value:
return self.add(LoadStatic(dict_rprimitive, 'globals', self.module_name))
Expand Down
32 changes: 16 additions & 16 deletions mypyc/irbuild/classdef.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,12 @@ def transform_class_def(builder: IRBuilder, cdef: ClassDef) -> None:
builder.add(InitStatic(non_ext_class, cdef.name, builder.module_name, NAMESPACE_TYPE))

# Add the non-extension class to the dict
builder.primitive_op(dict_set_item_op,
[
builder.load_globals_dict(),
builder.load_static_unicode(cdef.name),
non_ext_class
], cdef.line)
builder.call_c(dict_set_item_op,
[
builder.load_globals_dict(),
builder.load_static_unicode(cdef.name),
non_ext_class
], cdef.line)

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

# Add it to the dict
builder.primitive_op(dict_set_item_op,
[
builder.load_globals_dict(),
builder.load_static_unicode(cdef.name),
tp,
], cdef.line)
builder.call_c(dict_set_item_op,
[
builder.load_globals_dict(),
builder.load_static_unicode(cdef.name),
tp,
], cdef.line)

return tp

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

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

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

# We add a __doc__ attribute so if the non-extension class is decorated with the
# dataclass decorator, dataclass will not try to look for __text_signature__.
Expand Down
12 changes: 6 additions & 6 deletions mypyc/irbuild/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
)
from mypyc.ir.rtypes import RTuple, object_rprimitive, is_none_rprimitive
from mypyc.ir.func_ir import FUNC_CLASSMETHOD, FUNC_STATICMETHOD
from mypyc.primitives.registry import name_ref_ops
from mypyc.primitives.registry import name_ref_ops, CFunctionDescription
from mypyc.primitives.generic_ops import iter_op
from mypyc.primitives.misc_ops import new_slice_op, ellipsis_op, type_op
from mypyc.primitives.list_ops import new_list_op, list_append_op, list_extend_op
Expand Down Expand Up @@ -491,8 +491,8 @@ def transform_set_expr(builder: IRBuilder, expr: SetExpr) -> Value:
def _visit_display(builder: IRBuilder,
items: List[Expression],
constructor_op: OpDescription,
append_op: OpDescription,
extend_op: OpDescription,
append_op: CFunctionDescription,
extend_op: CFunctionDescription,
line: int
) -> Value:
accepted_items = []
Expand All @@ -512,7 +512,7 @@ def _visit_display(builder: IRBuilder,
if result is None:
result = builder.primitive_op(constructor_op, initial_items, line)

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

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

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

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

comprehension_helper(builder, loop_params, gen_inner_stmts, o.line)
return d
Expand Down
19 changes: 10 additions & 9 deletions mypyc/irbuild/for_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
)
from mypyc.ir.ops import (
Value, BasicBlock, LoadInt, Branch, Register, AssignmentTarget, TupleGet,
AssignmentTargetTuple, TupleSet, OpDescription, BinaryIntOp
AssignmentTargetTuple, TupleSet, BinaryIntOp
)
from mypyc.ir.rtypes import (
RType, is_short_int_rprimitive, is_list_rprimitive, is_sequence_rprimitive,
RTuple, is_dict_rprimitive, short_int_rprimitive
)
from mypyc.primitives.registry import CFunctionDescription
from mypyc.primitives.dict_ops import (
dict_next_key_op, dict_next_value_op, dict_next_item_op, dict_check_size_op,
dict_key_iter_op, dict_value_iter_op, dict_item_iter_op
Expand Down Expand Up @@ -92,7 +93,7 @@ def translate_list_comprehension(builder: IRBuilder, gen: GeneratorExpr) -> Valu

def gen_inner_stmts() -> None:
e = builder.accept(gen.left_expr)
builder.primitive_op(list_append_op, [list_ops, e], gen.line)
builder.call_c(list_append_op, [list_ops, e], gen.line)

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

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

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

def gen_condition(self) -> None:
"""Get next key/value pair, set new offset, and check if we should continue."""
builder = self.builder
line = self.line
self.next_tuple = self.builder.primitive_op(
self.next_tuple = self.builder.call_c(
self.dict_next_op, [builder.read(self.iter_target, line),
builder.read(self.offset_target, line)], line)

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

def gen_cleanup(self) -> None:
# Same as for generic ForIterable.
Expand Down
8 changes: 4 additions & 4 deletions mypyc/irbuild/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,10 @@ def transform_decorator(builder: IRBuilder, dec: Decorator) -> None:
decorated_func = load_decorated_func(builder, dec.func, orig_func)

# Set the callable object representing the decorated function as a global.
builder.primitive_op(dict_set_item_op,
[builder.load_globals_dict(),
builder.load_static_unicode(dec.func.name), decorated_func],
decorated_func.line)
builder.call_c(dict_set_item_op,
[builder.load_globals_dict(),
builder.load_static_unicode(dec.func.name), decorated_func],
decorated_func.line)

builder.functions.append(func_ir)

Expand Down
4 changes: 2 additions & 2 deletions mypyc/irbuild/ll_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ def py_call(self,
# don't have an extend method.
pos_args_list = self.primitive_op(new_list_op, pos_arg_values, line)
for star_arg_value in star_arg_values:
self.primitive_op(list_extend_op, [pos_args_list, star_arg_value], line)
self.call_c(list_extend_op, [pos_args_list, star_arg_value], line)
pos_args_tuple = self.call_c(list_tuple_op, [pos_args_list], line)

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

self.primitive_op(
self.call_c(
dict_update_in_display_op,
[result, value],
line=line
Expand Down
6 changes: 3 additions & 3 deletions mypyc/irbuild/specialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,11 @@ def dict_methods_fast_path(
# Note that it is not safe to use fast methods on dict subclasses, so
# the corresponding helpers in CPy.h fallback to (inlined) generic logic.
if attr == 'keys':
return builder.primitive_op(dict_keys_op, [obj], expr.line)
return builder.call_c(dict_keys_op, [obj], expr.line)
elif attr == 'values':
return builder.primitive_op(dict_values_op, [obj], expr.line)
return builder.call_c(dict_values_op, [obj], expr.line)
else:
return builder.primitive_op(dict_items_op, [obj], expr.line)
return builder.call_c(dict_items_op, [obj], expr.line)


@specialize_function('builtins.tuple')
Expand Down
4 changes: 2 additions & 2 deletions mypyc/irbuild/statement.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ def transform_import(builder: IRBuilder, node: Import) -> None:

# Python 3.7 has a nice 'PyImport_GetModule' function that we can't use :(
mod_dict = builder.primitive_op(get_module_dict_op, [], node.line)
obj = builder.primitive_op(dict_get_item_op,
[mod_dict, builder.load_static_unicode(base)], node.line)
obj = builder.call_c(dict_get_item_op,
[mod_dict, builder.load_static_unicode(base)], node.line)
builder.gen_method_call(
globals, '__setitem__', [builder.load_static_unicode(name), obj],
result_type=None, line=node.line)
Expand Down
Loading