diff --git a/mypyc/irbuild/classdef.py b/mypyc/irbuild/classdef.py index 68d5ff3ee1bd..19033b19bf14 100644 --- a/mypyc/irbuild/classdef.py +++ b/mypyc/irbuild/classdef.py @@ -8,7 +8,7 @@ ) from mypyc.ir.ops import ( Value, Call, LoadErrorValue, LoadStatic, InitStatic, TupleSet, SetAttr, Return, - BasicBlock, Branch, MethodCall, NAMESPACE_TYPE + BasicBlock, Branch, MethodCall, NAMESPACE_TYPE, LoadAddress ) from mypyc.ir.rtypes import ( RInstance, object_rprimitive, bool_rprimitive, dict_rprimitive, is_optional_type, @@ -227,7 +227,8 @@ def find_non_ext_metaclass(builder: IRBuilder, cdef: ClassDef, bases: Value) -> if cdef.metaclass: declared_metaclass = builder.accept(cdef.metaclass) else: - declared_metaclass = builder.primitive_op(type_object_op, [], cdef.line) + declared_metaclass = builder.add(LoadAddress(type_object_op.type, + type_object_op.src, cdef.line)) return builder.primitive_op(py_calc_meta_op, [declared_metaclass, bases], cdef.line) @@ -279,7 +280,7 @@ def add_non_ext_class_attr(builder: IRBuilder, # which attributes to compute on. # TODO: Maybe generate more precise types for annotations key = builder.load_static_unicode(lvalue.name) - typ = builder.primitive_op(type_object_op, [], stmt.line) + typ = builder.add(LoadAddress(type_object_op.type, type_object_op.src, 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: @@ -393,7 +394,8 @@ def gen_glue_ne_method(builder: IRBuilder, cls: ClassIR, line: int) -> FuncIR: # If __eq__ returns NotImplemented, then __ne__ should also not_implemented_block, regular_block = BasicBlock(), BasicBlock() eqval = builder.add(MethodCall(args[0], '__eq__', [args[1]], line)) - not_implemented = builder.primitive_op(not_implemented_op, [], line) + not_implemented = builder.add(LoadAddress(not_implemented_op.type, + not_implemented_op.src, line)) builder.add(Branch( builder.binary_op(eqval, not_implemented, 'is', line), not_implemented_block, @@ -521,7 +523,7 @@ def dataclass_non_ext_info(builder: IRBuilder, cdef: ClassDef) -> Optional[NonEx builder.call_c(dict_new_op, [], cdef.line), builder.add(TupleSet([], cdef.line)), builder.call_c(dict_new_op, [], cdef.line), - builder.primitive_op(type_object_op, [], cdef.line), + builder.add(LoadAddress(type_object_op.type, type_object_op.src, cdef.line)) ) else: return None diff --git a/mypyc/primitives/int_ops.py b/mypyc/primitives/int_ops.py index e0416a0d256b..ee9a76cb0c67 100644 --- a/mypyc/primitives/int_ops.py +++ b/mypyc/primitives/int_ops.py @@ -13,20 +13,18 @@ str_rprimitive, RType ) from mypyc.primitives.registry import ( - name_ref_op, name_emit, - c_unary_op, CFunctionDescription, c_function_op, c_binary_op, c_custom_op + load_address_op, c_unary_op, CFunctionDescription, c_function_op, c_binary_op, c_custom_op ) # These int constructors produce object_rprimitives that then need to be unboxed # I guess unboxing ourselves would save a check and branch though? # Get the type object for 'builtins.int'. -# For ordinary calls to int() we use a name_ref to the type -name_ref_op('builtins.int', - result_type=object_rprimitive, - error_kind=ERR_NEVER, - emit=name_emit('&PyLong_Type', target_type='PyObject *'), - is_borrowed=True) +# For ordinary calls to int() we use a load_address to the type +load_address_op( + name='builtins.int', + type=object_rprimitive, + src='PyLong_Type') # Convert from a float to int. We could do a bit better directly. c_function_op( diff --git a/mypyc/primitives/list_ops.py b/mypyc/primitives/list_ops.py index 7768f2bd0af4..ca4110be2bf7 100644 --- a/mypyc/primitives/list_ops.py +++ b/mypyc/primitives/list_ops.py @@ -8,17 +8,15 @@ c_int_rprimitive ) from mypyc.primitives.registry import ( - name_ref_op, custom_op, name_emit, - call_emit, c_function_op, c_binary_op, c_method_op + custom_op, load_address_op, call_emit, c_function_op, c_binary_op, c_method_op ) # Get the 'builtins.list' type object. -name_ref_op('builtins.list', - result_type=object_rprimitive, - error_kind=ERR_NEVER, - emit=name_emit('&PyList_Type', target_type='PyObject *'), - is_borrowed=True) +load_address_op( + name='builtins.list', + type=object_rprimitive, + src='PyList_Type') # list(obj) to_list = c_function_op( diff --git a/mypyc/primitives/misc_ops.py b/mypyc/primitives/misc_ops.py index bab25ef58a07..9ff548acee9e 100644 --- a/mypyc/primitives/misc_ops.py +++ b/mypyc/primitives/misc_ops.py @@ -7,7 +7,7 @@ ) from mypyc.primitives.registry import ( name_ref_op, simple_emit, unary_op, func_op, custom_op, call_emit, name_emit, - call_negative_magic_emit, c_function_op, c_custom_op + call_negative_magic_emit, c_function_op, c_custom_op, load_address_op ) @@ -46,11 +46,10 @@ is_borrowed=True) # Get the boxed NotImplemented object -not_implemented_op = name_ref_op(name='builtins.NotImplemented', - result_type=object_rprimitive, - error_kind=ERR_NEVER, - emit=name_emit('Py_NotImplemented'), - is_borrowed=True) +not_implemented_op = load_address_op( + name='builtins.NotImplemented', + type=object_rprimitive, + src='_Py_NotImplementedStruct') # id(obj) c_function_op( @@ -201,12 +200,10 @@ error_kind=ERR_NEVER) # Get 'builtins.type' (base class of all classes) -type_object_op = name_ref_op( - 'builtins.type', - result_type=object_rprimitive, - error_kind=ERR_NEVER, - emit=name_emit('&PyType_Type', target_type='PyObject *'), - is_borrowed=True) +type_object_op = load_address_op( + name='builtins.type', + type=object_rprimitive, + src='PyType_Type') # Create a heap type based on a template non-heap type. # See CPyType_FromTemplate for more docs. diff --git a/mypyc/primitives/registry.py b/mypyc/primitives/registry.py index 57f8c038d278..1053d2721494 100644 --- a/mypyc/primitives/registry.py +++ b/mypyc/primitives/registry.py @@ -56,12 +56,10 @@ ('priority', int)]) # A description for C load operations including LoadGlobal and LoadAddress -CLoadDescription = NamedTuple( - 'CLoadDescription', [('name', str), - ('return_type', RType), - ('identifier', str), # name of the target to load - ('cast_str', str), # string represents optional type cast - ('load_address', bool)]) # True for LoadAddress otherwise LoadGlobal +LoadAddressDescription = NamedTuple( + 'LoadAddressDescription', [('name', str), + ('type', RType), + ('src', str)]) # name of the target to load # Primitive binary ops (key is operator such as '+') binary_ops = {} # type: Dict[str, List[OpDescription]] @@ -90,9 +88,6 @@ # CallC op for unary ops c_unary_ops = {} # type: Dict[str, List[CFunctionDescription]] -# LoadGlobal/LoadAddress op for reading global names -c_name_ref_ops = {} # type: Dict[str, CLoadDescription] - builtin_names = {} # type: Dict[str, Tuple[RType, str]] @@ -489,23 +484,12 @@ def c_unary_op(name: str, return desc -def c_name_ref_op(name: str, - return_type: RType, - identifier: str, - cast_str: Optional[str] = None, - load_address: bool = False) -> CLoadDescription: - assert name not in c_name_ref_ops, 'already defined: %s' % name - cast_str = cast_str if cast_str else "" - desc = CLoadDescription(name, return_type, identifier, cast_str, load_address) - c_name_ref_ops[name] = desc - return desc - - def load_address_op(name: str, type: RType, - src: str) -> None: + src: str) -> LoadAddressDescription: assert name not in builtin_names, 'already defined: %s' % name builtin_names[name] = (type, src) + return LoadAddressDescription(name, type, src) # Import various modules that set up global state. diff --git a/mypyc/primitives/str_ops.py b/mypyc/primitives/str_ops.py index 69a972bf0715..778b2f3bb56f 100644 --- a/mypyc/primitives/str_ops.py +++ b/mypyc/primitives/str_ops.py @@ -2,22 +2,21 @@ from typing import List, Callable -from mypyc.ir.ops import ERR_MAGIC, ERR_NEVER, EmitterInterface, EmitCallback +from mypyc.ir.ops import ERR_MAGIC, EmitterInterface, EmitCallback from mypyc.ir.rtypes import ( RType, object_rprimitive, str_rprimitive, bool_rprimitive, int_rprimitive, list_rprimitive ) from mypyc.primitives.registry import ( - binary_op, simple_emit, name_ref_op, method_op, call_emit, name_emit, - c_method_op, c_binary_op, c_function_op + binary_op, simple_emit, method_op, call_emit, c_method_op, c_binary_op, c_function_op, + load_address_op ) # Get the 'str' type object. -name_ref_op('builtins.str', - result_type=object_rprimitive, - error_kind=ERR_NEVER, - emit=name_emit('&PyUnicode_Type', target_type='PyObject *'), - is_borrowed=True) +load_address_op( + name='builtins.str', + type=object_rprimitive, + src='PyUnicode_Type') # str(obj) c_function_op( diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index 951cf06a9809..410e667d2b2c 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -1243,7 +1243,7 @@ def call_python_function(x): r0, r1, r2 :: object r3 :: int L0: - r0 = int + r0 = load_address PyLong_Type r1 = box(int, x) r2 = py_call(r0, r1) r3 = unbox(int, r2) @@ -1294,7 +1294,7 @@ def call_python_function_with_keyword_arg(x): r5 :: object r6 :: int L0: - r0 = int + r0 = load_address PyLong_Type r1 = unicode_3 :: static ('base') r2 = (x) :: tuple r3 = box(short_int, 4) @@ -1696,7 +1696,7 @@ def foo(x): r3 :: __main__.B r4 :: __main__.A L0: - r0 = int + r0 = load_address PyLong_Type r1 = PyObject_IsInstance(x, r0) r2 = truncate r1: int32 to builtins.bool if r2 goto L1 else goto L2 :: bool @@ -2688,11 +2688,11 @@ L4: r23 = CPyDict_SetItem(r11, r22, r21) r24 = unicode_5 :: static ('Lol') r25 = unicode_6 :: static ('a') - r26 = int + r26 = load_address PyLong_Type r27 = (r25, r26) r28 = box(tuple[str, object], r27) r29 = unicode_7 :: static ('b') - r30 = str + r30 = load_address PyUnicode_Type r31 = (r29, r30) r32 = box(tuple[str, object], r31) r33 = (r28, r32) @@ -2717,7 +2717,7 @@ L4: r52 = __main__.globals :: static r53 = unicode_2 :: static ('List') r54 = CPyDict_GetItem(r52, r53) - r55 = int + r55 = load_address PyLong_Type r56 = PyObject_GetItem(r54, r55) r57 = __main__.globals :: static r58 = unicode_10 :: static ('Foo') @@ -2820,7 +2820,7 @@ def A.__eq__(self, x): self :: __main__.A x, r0 :: object L0: - r0 = NotImplemented + r0 = load_address _Py_NotImplementedStruct return r0 def A.__ne__(self, rhs): self :: __main__.A @@ -2829,7 +2829,7 @@ def A.__ne__(self, rhs): r4 :: object L0: r0 = self.__eq__(rhs) - r1 = NotImplemented + r1 = load_address _Py_NotImplementedStruct r2 = r0 is r1 if r2 goto L2 else goto L1 :: bool L1: diff --git a/mypyc/test-data/irbuild-classes.test b/mypyc/test-data/irbuild-classes.test index d92291e29c95..3ad447c458d6 100644 --- a/mypyc/test-data/irbuild-classes.test +++ b/mypyc/test-data/irbuild-classes.test @@ -832,7 +832,7 @@ def Base.__ne__(self, rhs): r4 :: object L0: r0 = self.__eq__(rhs) - r1 = NotImplemented + r1 = load_address _Py_NotImplementedStruct r2 = r0 is r1 if r2 goto L2 else goto L1 :: bool L1: @@ -953,7 +953,7 @@ def Derived.__ne__(self, rhs): r4 :: object L0: r0 = self.__eq__(rhs) - r1 = NotImplemented + r1 = load_address _Py_NotImplementedStruct r2 = r0 is r1 if r2 goto L2 else goto L1 :: bool L1: diff --git a/mypyc/test-data/irbuild-optional.test b/mypyc/test-data/irbuild-optional.test index 3f25bf103c80..320186fde8d8 100644 --- a/mypyc/test-data/irbuild-optional.test +++ b/mypyc/test-data/irbuild-optional.test @@ -295,7 +295,7 @@ def f(x): r5 :: __main__.A r6 :: int L0: - r0 = int + r0 = load_address PyLong_Type r1 = PyObject_IsInstance(x, r0) r2 = truncate r1: int32 to builtins.bool if r2 goto L1 else goto L2 :: bool diff --git a/mypyc/test-data/refcount.test b/mypyc/test-data/refcount.test index 39db7d05f017..20025102e4c8 100644 --- a/mypyc/test-data/refcount.test +++ b/mypyc/test-data/refcount.test @@ -734,7 +734,7 @@ def g(x): r5 :: object r6 :: int L0: - r0 = int + r0 = load_address PyLong_Type r1 = unicode_1 :: static ('base') r2 = (x) :: tuple r3 = box(short_int, 4)