diff --git a/mypyc/codegen/emitfunc.py b/mypyc/codegen/emitfunc.py index 0dc0dd96900c..537f47cf6acd 100644 --- a/mypyc/codegen/emitfunc.py +++ b/mypyc/codegen/emitfunc.py @@ -477,7 +477,8 @@ def visit_get_element_ptr(self, op: GetElementPtr) -> None: # TODO: support tuple type assert isinstance(op.src_type, RStruct) assert op.field in op.src_type.names, "Invalid field name." - self.emit_line('%s = &%s.%s;' % (dest, src, op.field)) + self.emit_line('%s = (%s)&((%s *)%s)->%s;' % (dest, op.type._ctype, op.src_type.name, + src, op.field)) # Helpers diff --git a/mypyc/ir/ops.py b/mypyc/ir/ops.py index 12d7e32db230..e90ccafd29ac 100644 --- a/mypyc/ir/ops.py +++ b/mypyc/ir/ops.py @@ -25,8 +25,7 @@ from mypyc.ir.rtypes import ( RType, RInstance, RTuple, RVoid, is_bool_rprimitive, is_int_rprimitive, is_short_int_rprimitive, is_none_rprimitive, object_rprimitive, bool_rprimitive, - short_int_rprimitive, int_rprimitive, void_rtype, is_c_py_ssize_t_rprimitive, - c_pyssize_t_rprimitive + short_int_rprimitive, int_rprimitive, void_rtype, pointer_rprimitive, is_pointer_rprimitive ) from mypyc.common import short_name @@ -1360,7 +1359,7 @@ def __init__(self, type: RType, src: Value, line: int = -1) -> None: self.type = type # TODO: for now we enforce that the src memory address should be Py_ssize_t # later we should also support same width unsigned int - assert is_c_py_ssize_t_rprimitive(src.type) + assert is_pointer_rprimitive(src.type) self.src = src def sources(self) -> List[Value]: @@ -1379,7 +1378,7 @@ class GetElementPtr(RegisterOp): def __init__(self, src: Value, src_type: RType, field: str, line: int = -1) -> None: super().__init__(line) - self.type = c_pyssize_t_rprimitive + self.type = pointer_rprimitive self.src = src self.src_type = src_type self.field = field @@ -1388,7 +1387,7 @@ def sources(self) -> List[Value]: return [self.src] def to_str(self, env: Environment) -> str: - return env.format("%r = get_element_ptr %r %r :: %r", self, self.src, + return env.format("%r = get_element_ptr %r %s :: %r", self, self.src, self.field, self.src_type) def accept(self, visitor: 'OpVisitor[T]') -> T: diff --git a/mypyc/ir/rtypes.py b/mypyc/ir/rtypes.py index 46be550cec05..fe5abe4fb1b9 100644 --- a/mypyc/ir/rtypes.py +++ b/mypyc/ir/rtypes.py @@ -182,8 +182,10 @@ def __init__(self, self.size = size # TODO: For low-level integers, they actually don't have undefined values # we need to figure out some way to represent here. - if ctype in ('CPyTagged', 'int32_t', 'int64_t'): + if ctype == 'CPyTagged': self.c_undefined = 'CPY_INT_TAG' + elif ctype in ('int32_t', 'int64_t', 'CPyPtr'): + self.c_undefined = '0' elif ctype == 'PyObject *': # Boxed types use the null pointer as the error value. self.c_undefined = 'NULL' @@ -254,6 +256,10 @@ def __repr__(self) -> str: else: c_pyssize_t_rprimitive = int64_rprimitive +# low level pointer, represented as integer in C backends +pointer_rprimitive = RPrimitive('ptr', is_unboxed=True, is_refcounted=False, + ctype='CPyPtr') # type: Final + # Floats are represent as 'float' PyObject * values. (In the future # we'll likely switch to a more efficient, unboxed representation.) float_rprimitive = RPrimitive('builtins.float', is_unboxed=False, @@ -311,6 +317,10 @@ def is_c_py_ssize_t_rprimitive(rtype: RType) -> bool: return rtype is c_pyssize_t_rprimitive +def is_pointer_rprimitive(rtype: RType) -> bool: + return rtype is pointer_rprimitive + + def is_float_rprimitive(rtype: RType) -> bool: return isinstance(rtype, RPrimitive) and rtype.name == 'builtins.float' @@ -514,12 +524,8 @@ def compute_aligned_offsets_and_size(types: List[RType]) -> Tuple[List[int], int return offsets, final_size -class StructInfo: - """Struct-like type Infomation - - StructInfo should work with registry to ensure constraints like the unique naming - constraint for struct type - """ +class RStruct(RType): + """Represent CPython structs""" def __init__(self, name: str, names: List[str], @@ -532,31 +538,7 @@ def __init__(self, for i in range(len(self.types) - len(self.names)): self.names.append('_item' + str(i)) self.offsets, self.size = compute_aligned_offsets_and_size(types) - - -class RStruct(RType): - """Represent CPython structs""" - def __init__(self, - info: StructInfo) -> None: - self.info = info - self.name = self.info.name - self._ctype = self.info.name - - @property - def names(self) -> List[str]: - return self.info.names - - @property - def types(self) -> List[RType]: - return self.info.types - - @property - def offsets(self) -> List[int]: - return self.info.offsets - - @property - def size(self) -> int: - return self.info.size + self._ctype = name def accept(self, visitor: 'RTypeVisitor[T]') -> T: return visitor.visit_rstruct(self) @@ -571,10 +553,11 @@ def __repr__(self) -> str: in zip(self.names, self.types))) def __eq__(self, other: object) -> bool: - return isinstance(other, RStruct) and self.info == other.info + return (isinstance(other, RStruct) and self.name == other.name + and self.names == other.names and self.types == other.types) def __hash__(self) -> int: - return hash(self.info) + return hash((self.name, tuple(self.names), tuple(self.types))) def serialize(self) -> JsonDict: assert False @@ -687,3 +670,14 @@ def optional_value_type(rtype: RType) -> Optional[RType]: def is_optional_type(rtype: RType) -> bool: """Is rtype an optional type with exactly two union items?""" return optional_value_type(rtype) is not None + + +PyObject = RStruct( + name='PyObject', + names=['ob_refcnt', 'ob_type'], + types=[c_pyssize_t_rprimitive, pointer_rprimitive]) + +PyVarObject = RStruct( + name='PyVarObject', + names=['ob_base', 'ob_size'], + types=[PyObject, c_pyssize_t_rprimitive]) diff --git a/mypyc/irbuild/builder.py b/mypyc/irbuild/builder.py index 1b087c501aa3..53bd50f2a845 100644 --- a/mypyc/irbuild/builder.py +++ b/mypyc/irbuild/builder.py @@ -44,7 +44,7 @@ from mypyc.ir.func_ir import FuncIR, INVALID_FUNC_DEF from mypyc.ir.class_ir import ClassIR, NonExtClassInfo from mypyc.primitives.registry import func_ops, CFunctionDescription, c_function_ops -from mypyc.primitives.list_ops import list_len_op, to_list, list_pop_last +from mypyc.primitives.list_ops import to_list, list_pop_last from mypyc.primitives.dict_ops import dict_get_item_op, dict_set_item_op from mypyc.primitives.generic_ops import py_setattr_op, iter_op, next_op from mypyc.primitives.misc_ops import true_op, false_op, import_op @@ -238,6 +238,9 @@ def binary_int_op(self, type: RType, lhs: Value, rhs: Value, op: int, line: int) def compare_tagged(self, lhs: Value, rhs: Value, op: str, line: int) -> Value: return self.builder.compare_tagged(lhs, rhs, op, line) + def list_len(self, val: Value, line: int) -> Value: + return self.builder.list_len(val, line) + @property def environment(self) -> Environment: return self.builder.environment @@ -508,7 +511,7 @@ def process_iterator_tuple_assignment(self, if target.star_idx is not None: post_star_vals = target.items[split_idx + 1:] iter_list = self.call_c(to_list, [iterator], line) - iter_list_len = self.primitive_op(list_len_op, [iter_list], line) + iter_list_len = self.list_len(iter_list, line) post_star_len = self.add(LoadInt(len(post_star_vals))) condition = self.binary_op(post_star_len, iter_list_len, '<=', line) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 56e8cf8b816f..a1e3583aa1d0 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -29,7 +29,6 @@ from mypyc.primitives.exc_ops import no_err_occurred_op from mypyc.irbuild.builder import IRBuilder - GenFunc = Callable[[], None] @@ -333,6 +332,9 @@ def gen_cleanup(self) -> None: def load_len(self, expr: Union[Value, AssignmentTarget]) -> Value: """A helper to get collection length, used by several subclasses.""" + val = self.builder.read(expr, self.line) + if is_list_rprimitive(val.type): + return self.builder.builder.list_len(self.builder.read(expr, self.line), self.line) return self.builder.builder.builtin_call( [self.builder.read(expr, self.line)], 'builtins.len', diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index f8d5e5d8e04f..216f3f582a96 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -21,12 +21,13 @@ Assign, Branch, Goto, Call, Box, Unbox, Cast, GetAttr, LoadStatic, MethodCall, PrimitiveOp, OpDescription, RegisterOp, CallC, Truncate, RaiseStandardError, Unreachable, LoadErrorValue, LoadGlobal, - NAMESPACE_TYPE, NAMESPACE_MODULE, NAMESPACE_STATIC, BinaryIntOp + NAMESPACE_TYPE, NAMESPACE_MODULE, NAMESPACE_STATIC, BinaryIntOp, GetElementPtr, + LoadMem ) from mypyc.ir.rtypes import ( RType, RUnion, RInstance, optional_value_type, int_rprimitive, float_rprimitive, bool_rprimitive, list_rprimitive, str_rprimitive, is_none_rprimitive, object_rprimitive, - c_pyssize_t_rprimitive, is_short_int_rprimitive, is_tagged + c_pyssize_t_rprimitive, is_short_int_rprimitive, is_tagged, PyVarObject, short_int_rprimitive ) from mypyc.ir.func_ir import FuncDecl, FuncSignature from mypyc.ir.class_ir import ClassIR, all_concrete_classes @@ -40,7 +41,7 @@ c_binary_ops, c_unary_ops ) from mypyc.primitives.list_ops import ( - list_extend_op, list_len_op, new_list_op + list_extend_op, new_list_op ) from mypyc.primitives.tuple_ops import list_tuple_op, new_tuple_op from mypyc.primitives.dict_ops import ( @@ -703,7 +704,7 @@ def add_bool_branch(self, value: Value, true: BasicBlock, false: BasicBlock) -> zero = self.add(LoadInt(0)) value = self.binary_op(value, zero, '!=', value.line) elif is_same_type(value.type, list_rprimitive): - length = self.primitive_op(list_len_op, [value], value.line) + length = self.list_len(value, value.line) zero = self.add(LoadInt(0)) value = self.binary_op(length, zero, '!=', value.line) elif (isinstance(value.type, RInstance) and value.type.class_ir.is_ext_class @@ -810,6 +811,12 @@ def matching_call_c(self, def binary_int_op(self, type: RType, lhs: Value, rhs: Value, op: int, line: int) -> Value: return self.add(BinaryIntOp(type, lhs, rhs, op, line)) + def list_len(self, val: Value, line: int) -> Value: + elem_address = self.add(GetElementPtr(val, PyVarObject, 'ob_size')) + size_value = self.add(LoadMem(c_pyssize_t_rprimitive, elem_address)) + offset = self.add(LoadInt(1, -1, rtype=c_pyssize_t_rprimitive)) + return self.binary_int_op(short_int_rprimitive, size_value, offset, + BinaryIntOp.LEFT_SHIFT, -1) # Internal helpers def decompose_union_helper(self, diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index d10387c26f6b..bb6b146f413e 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -18,11 +18,11 @@ from mypy.types import AnyType, TypeOfAny from mypyc.ir.ops import ( - Value, BasicBlock, LoadInt, RaiseStandardError, Unreachable, OpDescription + Value, BasicBlock, LoadInt, RaiseStandardError, Unreachable, OpDescription, ) from mypyc.ir.rtypes import ( RType, RTuple, str_rprimitive, list_rprimitive, dict_rprimitive, set_rprimitive, - bool_rprimitive, is_dict_rprimitive + bool_rprimitive, is_dict_rprimitive, is_list_rprimitive, ) from mypyc.primitives.dict_ops import dict_keys_op, dict_values_op, dict_items_op from mypyc.primitives.misc_ops import true_op, false_op @@ -75,6 +75,9 @@ def translate_len( # though we still need to evaluate it. builder.accept(expr.args[0]) return builder.add(LoadInt(len(expr_rtype.types))) + elif is_list_rprimitive(expr_rtype): + obj = builder.accept(expr.args[0]) + return builder.list_len(obj, -1) return None diff --git a/mypyc/lib-rt/mypyc_util.h b/mypyc/lib-rt/mypyc_util.h index 217533de9d32..ed4e09c14cd1 100644 --- a/mypyc/lib-rt/mypyc_util.h +++ b/mypyc/lib-rt/mypyc_util.h @@ -32,6 +32,7 @@ #define CPy_XDECREF(p) Py_XDECREF(p) typedef size_t CPyTagged; +typedef size_t CPyPtr; #define CPY_INT_BITS (CHAR_BIT * sizeof(CPyTagged)) diff --git a/mypyc/primitives/list_ops.py b/mypyc/primitives/list_ops.py index 24546e9f1914..7768f2bd0af4 100644 --- a/mypyc/primitives/list_ops.py +++ b/mypyc/primitives/list_ops.py @@ -8,7 +8,7 @@ c_int_rprimitive ) from mypyc.primitives.registry import ( - name_ref_op, func_op, custom_op, name_emit, + name_ref_op, custom_op, name_emit, call_emit, c_function_op, c_binary_op, c_method_op ) @@ -146,11 +146,3 @@ def emit_len(emitter: EmitterInterface, args: List[str], dest: str) -> None: emitter.emit_declaration('Py_ssize_t %s;' % temp) emitter.emit_line('%s = PyList_GET_SIZE(%s);' % (temp, args[0])) emitter.emit_line('%s = CPyTagged_ShortFromSsize_t(%s);' % (dest, temp)) - - -# len(list) -list_len_op = func_op(name='builtins.len', - arg_types=[list_rprimitive], - result_type=short_int_rprimitive, - error_kind=ERR_NEVER, - emit=emit_len) diff --git a/mypyc/primitives/struct_regsitry.py b/mypyc/primitives/struct_regsitry.py deleted file mode 100644 index 4233889c8fb8..000000000000 --- a/mypyc/primitives/struct_regsitry.py +++ /dev/null @@ -1,24 +0,0 @@ -"""Struct registries for C backend""" - -from typing import List, NamedTuple -from mypyc.ir.rtypes import RType - -CStructDescription = NamedTuple( - 'CStructDescription', [('name', str), - ('names', List[str]), - ('types', List[RType])]) - - -def c_struct(name: str, - names: List[str], - types: List[RType]) -> CStructDescription: - """Define a known C struct for generating IR to manipulate it - - name: The name of the C struct - types: type of each field - names: name of each field - TODO: the names list can be empty in the future when we merge Tuple as part of Struct - """ - return CStructDescription(name, names, types) - -# TODO: create PyVarObject, to do which we probably need PyObject diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index 6a6cd086642c..951cf06a9809 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -1400,12 +1400,16 @@ L6: unreachable def lst(x): x :: list - r0 :: short_int - r1 :: bool + r0 :: ptr + r1 :: native_int + r2 :: short_int + r3 :: bool L0: - r0 = len x :: list - r1 = r0 != 0 - if r1 goto L1 else goto L2 :: bool + r0 = get_element_ptr x ob_size :: PyVarObject + r1 = load_mem r0 :: native_int* + r2 = r1 << 1 + r3 = r2 != 0 + if r3 goto L1 else goto L2 :: bool L1: return 2 L2: @@ -2007,20 +2011,23 @@ def f(): r0 :: list r1, r2, r3 :: object r4 :: list - r5, r6 :: short_int - r7 :: bool - r8 :: object - x, r9 :: int - r10 :: bool - r11 :: native_int - r12, r13, r14, r15 :: bool - r16 :: bool - r17 :: native_int - r18, r19, r20, r21 :: bool - r22 :: int - r23 :: object - r24 :: int32 - r25 :: short_int + r5 :: short_int + r6 :: ptr + r7 :: native_int + r8 :: short_int + r9 :: bool + r10 :: object + x, r11 :: int + r12 :: bool + r13 :: native_int + r14, r15, r16, r17 :: bool + r18 :: bool + r19 :: native_int + r20, r21, r22, r23 :: bool + r24 :: int + r25 :: object + r26 :: int32 + r27 :: short_int L0: r0 = [] r1 = box(short_int, 2) @@ -2029,51 +2036,53 @@ L0: r4 = [r1, r2, r3] r5 = 0 L1: - r6 = len r4 :: list - r7 = r5 < r6 :: signed - if r7 goto L2 else goto L14 :: bool + r6 = get_element_ptr r4 ob_size :: PyVarObject + r7 = load_mem r6 :: native_int* + r8 = r7 << 1 + r9 = r5 < r8 :: signed + if r9 goto L2 else goto L14 :: bool L2: - r8 = r4[r5] :: unsafe list - r9 = unbox(int, r8) - x = r9 - r11 = x & 1 - r12 = r11 == 0 - if r12 goto L3 else goto L4 :: bool + r10 = r4[r5] :: unsafe list + r11 = unbox(int, r10) + x = r11 + r13 = x & 1 + r14 = r13 == 0 + if r14 goto L3 else goto L4 :: bool L3: - r13 = x != 4 - r10 = r13 + r15 = x != 4 + r12 = r15 goto L5 L4: - r14 = CPyTagged_IsEq_(x, 4) - r15 = !r14 - r10 = r15 + r16 = CPyTagged_IsEq_(x, 4) + r17 = !r16 + r12 = r17 L5: - if r10 goto L7 else goto L6 :: bool + if r12 goto L7 else goto L6 :: bool L6: goto L13 L7: - r17 = x & 1 - r18 = r17 == 0 - if r18 goto L8 else goto L9 :: bool + r19 = x & 1 + r20 = r19 == 0 + if r20 goto L8 else goto L9 :: bool L8: - r19 = x != 6 - r16 = r19 + r21 = x != 6 + r18 = r21 goto L10 L9: - r20 = CPyTagged_IsEq_(x, 6) - r21 = !r20 - r16 = r21 + r22 = CPyTagged_IsEq_(x, 6) + r23 = !r22 + r18 = r23 L10: - if r16 goto L12 else goto L11 :: bool + if r18 goto L12 else goto L11 :: bool L11: goto L13 L12: - r22 = CPyTagged_Multiply(x, x) - r23 = box(int, r22) - r24 = PyList_Append(r0, r23) + r24 = CPyTagged_Multiply(x, x) + r25 = box(int, r24) + r26 = PyList_Append(r0, r25) L13: - r25 = r5 + 2 - r5 = r25 + r27 = r5 + 2 + r5 = r27 goto L1 L14: return r0 @@ -2087,20 +2096,23 @@ def f(): r0 :: dict r1, r2, r3 :: object r4 :: list - r5, r6 :: short_int - r7 :: bool - r8 :: object - x, r9 :: int - r10 :: bool - r11 :: native_int - r12, r13, r14, r15 :: bool - r16 :: bool - r17 :: native_int - r18, r19, r20, r21 :: bool - r22 :: int - r23, r24 :: object - r25 :: int32 - r26 :: short_int + r5 :: short_int + r6 :: ptr + r7 :: native_int + r8 :: short_int + r9 :: bool + r10 :: object + x, r11 :: int + r12 :: bool + r13 :: native_int + r14, r15, r16, r17 :: bool + r18 :: bool + r19 :: native_int + r20, r21, r22, r23 :: bool + r24 :: int + r25, r26 :: object + r27 :: int32 + r28 :: short_int L0: r0 = PyDict_New() r1 = box(short_int, 2) @@ -2109,52 +2121,54 @@ L0: r4 = [r1, r2, r3] r5 = 0 L1: - r6 = len r4 :: list - r7 = r5 < r6 :: signed - if r7 goto L2 else goto L14 :: bool + r6 = get_element_ptr r4 ob_size :: PyVarObject + r7 = load_mem r6 :: native_int* + r8 = r7 << 1 + r9 = r5 < r8 :: signed + if r9 goto L2 else goto L14 :: bool L2: - r8 = r4[r5] :: unsafe list - r9 = unbox(int, r8) - x = r9 - r11 = x & 1 - r12 = r11 == 0 - if r12 goto L3 else goto L4 :: bool + r10 = r4[r5] :: unsafe list + r11 = unbox(int, r10) + x = r11 + r13 = x & 1 + r14 = r13 == 0 + if r14 goto L3 else goto L4 :: bool L3: - r13 = x != 4 - r10 = r13 + r15 = x != 4 + r12 = r15 goto L5 L4: - r14 = CPyTagged_IsEq_(x, 4) - r15 = !r14 - r10 = r15 + r16 = CPyTagged_IsEq_(x, 4) + r17 = !r16 + r12 = r17 L5: - if r10 goto L7 else goto L6 :: bool + if r12 goto L7 else goto L6 :: bool L6: goto L13 L7: - r17 = x & 1 - r18 = r17 == 0 - if r18 goto L8 else goto L9 :: bool + r19 = x & 1 + r20 = r19 == 0 + if r20 goto L8 else goto L9 :: bool L8: - r19 = x != 6 - r16 = r19 + r21 = x != 6 + r18 = r21 goto L10 L9: - r20 = CPyTagged_IsEq_(x, 6) - r21 = !r20 - r16 = r21 + r22 = CPyTagged_IsEq_(x, 6) + r23 = !r22 + r18 = r23 L10: - if r16 goto L12 else goto L11 :: bool + if r18 goto L12 else goto L11 :: bool L11: goto L13 L12: - r22 = CPyTagged_Multiply(x, x) - r23 = box(int, x) - r24 = box(int, r22) - r25 = CPyDict_SetItem(r0, r23, r24) + r24 = CPyTagged_Multiply(x, x) + r25 = box(int, x) + r26 = box(int, r24) + r27 = CPyDict_SetItem(r0, r25, r26) L13: - r26 = r5 + 2 - r5 = r26 + r28 = r5 + 2 + r5 = r28 goto L1 L14: return r0 @@ -2168,68 +2182,78 @@ def f(l: List[Tuple[int, int, int]]) -> List[int]: [out] def f(l): l :: list - r0, r1 :: short_int - r2 :: bool - r3 :: object + r0 :: short_int + r1 :: ptr + r2 :: native_int + r3 :: short_int + r4 :: bool + r5 :: object x, y, z :: int - r4 :: tuple[int, int, int] - r5, r6, r7 :: int - r8 :: short_int - r9 :: list - r10, r11 :: short_int - r12 :: bool - r13 :: object + r6 :: tuple[int, int, int] + r7, r8, r9 :: int + r10 :: short_int + r11 :: list + r12 :: short_int + r13 :: ptr + r14 :: native_int + r15 :: short_int + r16 :: bool + r17 :: object x0, y0, z0 :: int - r14 :: tuple[int, int, int] - r15, r16, r17, r18, r19 :: int - r20 :: object - r21 :: int32 - r22 :: short_int + r18 :: tuple[int, int, int] + r19, r20, r21, r22, r23 :: int + r24 :: object + r25 :: int32 + r26 :: short_int L0: r0 = 0 L1: - r1 = len l :: list - r2 = r0 < r1 :: signed - if r2 goto L2 else goto L4 :: bool + r1 = get_element_ptr l ob_size :: PyVarObject + r2 = load_mem r1 :: native_int* + r3 = r2 << 1 + r4 = r0 < r3 :: signed + if r4 goto L2 else goto L4 :: bool L2: - r3 = l[r0] :: unsafe list - r4 = unbox(tuple[int, int, int], r3) - r5 = r4[0] - x = r5 - r6 = r4[1] - y = r6 - r7 = r4[2] - z = r7 + r5 = l[r0] :: unsafe list + r6 = unbox(tuple[int, int, int], r5) + r7 = r6[0] + x = r7 + r8 = r6[1] + y = r8 + r9 = r6[2] + z = r9 L3: - r8 = r0 + 2 - r0 = r8 + r10 = r0 + 2 + r0 = r10 goto L1 L4: - r9 = [] - r10 = 0 + r11 = [] + r12 = 0 L5: - r11 = len l :: list - r12 = r10 < r11 :: signed - if r12 goto L6 else goto L8 :: bool + r13 = get_element_ptr l ob_size :: PyVarObject + r14 = load_mem r13 :: native_int* + r15 = r14 << 1 + r16 = r12 < r15 :: signed + if r16 goto L6 else goto L8 :: bool L6: - r13 = l[r10] :: unsafe list - r14 = unbox(tuple[int, int, int], r13) - r15 = r14[0] - x0 = r15 - r16 = r14[1] - y0 = r16 - r17 = r14[2] - z0 = r17 - r18 = CPyTagged_Add(x0, y0) - r19 = CPyTagged_Add(r18, z0) - r20 = box(int, r19) - r21 = PyList_Append(r9, r20) + r17 = l[r12] :: unsafe list + r18 = unbox(tuple[int, int, int], r17) + r19 = r18[0] + x0 = r19 + r20 = r18[1] + y0 = r20 + r21 = r18[2] + z0 = r21 + r22 = CPyTagged_Add(x0, y0) + r23 = CPyTagged_Add(r22, z0) + r24 = box(int, r23) + r25 = PyList_Append(r11, r24) L7: - r22 = r10 + 2 - r10 = r22 + r26 = r12 + 2 + r12 = r26 goto L5 L8: - return r9 + return r11 [case testProperty] class PropertyHolder: diff --git a/mypyc/test-data/irbuild-lists.test b/mypyc/test-data/irbuild-lists.test index 76c39fc183eb..cd28ec286791 100644 --- a/mypyc/test-data/irbuild-lists.test +++ b/mypyc/test-data/irbuild-lists.test @@ -120,10 +120,14 @@ def f(a: List[int]) -> int: [out] def f(a): a :: list - r0 :: short_int + r0 :: ptr + r1 :: native_int + r2 :: short_int L0: - r0 = len a :: list - return r0 + r0 = get_element_ptr a ob_size :: PyVarObject + r1 = load_mem r0 :: native_int* + r2 = r1 << 1 + return r2 [case testListAppend] from typing import List @@ -152,29 +156,33 @@ def increment(l: List[int]) -> List[int]: [out] def increment(l): l :: list - r0, r1 :: short_int + r0 :: ptr + r1 :: native_int + r2, r3 :: short_int i :: int - r2 :: bool - r3 :: object - r4, r5 :: object - r6 :: bool - r7 :: short_int + r4 :: bool + r5 :: object + r6, r7 :: object + r8 :: bool + r9 :: short_int L0: - r0 = len l :: list - r1 = 0 - i = r1 + r0 = get_element_ptr l ob_size :: PyVarObject + r1 = load_mem r0 :: native_int* + r2 = r1 << 1 + r3 = 0 + i = r3 L1: - r2 = r1 < r0 :: signed - if r2 goto L2 else goto L4 :: bool + r4 = r3 < r2 :: signed + if r4 goto L2 else goto L4 :: bool L2: - r3 = CPyList_GetItem(l, i) - r4 = box(short_int, 2) - r5 = PyNumber_InPlaceAdd(r3, r4) - r6 = CPyList_SetItem(l, i, r5) + r5 = CPyList_GetItem(l, i) + r6 = box(short_int, 2) + r7 = PyNumber_InPlaceAdd(r5, r6) + r8 = CPyList_SetItem(l, i, r7) L3: - r7 = r1 + 2 - r1 = r7 - i = r7 + r9 = r3 + 2 + r3 = r9 + i = r9 goto L1 L4: return l diff --git a/mypyc/test-data/irbuild-statements.test b/mypyc/test-data/irbuild-statements.test index a3768d343cfb..39b5958cede9 100644 --- a/mypyc/test-data/irbuild-statements.test +++ b/mypyc/test-data/irbuild-statements.test @@ -326,27 +326,32 @@ def f(ls: List[int]) -> int: def f(ls): ls :: list y :: int - r0, r1 :: short_int - r2 :: bool - r3 :: object - x, r4, r5 :: int - r6 :: short_int + r0 :: short_int + r1 :: ptr + r2 :: native_int + r3 :: short_int + r4 :: bool + r5 :: object + x, r6, r7 :: int + r8 :: short_int L0: y = 0 r0 = 0 L1: - r1 = len ls :: list - r2 = r0 < r1 :: signed - if r2 goto L2 else goto L4 :: bool + r1 = get_element_ptr ls ob_size :: PyVarObject + r2 = load_mem r1 :: native_int* + r3 = r2 << 1 + r4 = r0 < r3 :: signed + if r4 goto L2 else goto L4 :: bool L2: - r3 = ls[r0] :: unsafe list - r4 = unbox(int, r3) - x = r4 - r5 = CPyTagged_Add(y, x) - y = r5 + r5 = ls[r0] :: unsafe list + r6 = unbox(int, r5) + x = r6 + r7 = CPyTagged_Add(y, x) + y = r7 L3: - r6 = r0 + 2 - r0 = r6 + r8 = r0 + 2 + r0 = r8 goto L1 L4: return y @@ -869,36 +874,41 @@ def f(a): a :: list r0 :: short_int i :: int - r1, r2 :: short_int - r3 :: bool - r4 :: object - x, r5, r6 :: int - r7, r8 :: short_int - r9 :: None + r1 :: short_int + r2 :: ptr + r3 :: native_int + r4 :: short_int + r5 :: bool + r6 :: object + x, r7, r8 :: int + r9, r10 :: short_int + r11 :: None L0: r0 = 0 i = 0 r1 = 0 L1: - r2 = len a :: list - r3 = r1 < r2 :: signed - if r3 goto L2 else goto L4 :: bool + r2 = get_element_ptr a ob_size :: PyVarObject + r3 = load_mem r2 :: native_int* + r4 = r3 << 1 + r5 = r1 < r4 :: signed + if r5 goto L2 else goto L4 :: bool L2: - r4 = a[r1] :: unsafe list - r5 = unbox(int, r4) - x = r5 - r6 = CPyTagged_Add(i, x) + r6 = a[r1] :: unsafe list + r7 = unbox(int, r6) + x = r7 + r8 = CPyTagged_Add(i, x) L3: - r7 = r0 + 2 - r0 = r7 - i = r7 - r8 = r1 + 2 - r1 = r8 + r9 = r0 + 2 + r0 = r9 + i = r9 + r10 = r1 + 2 + r1 = r10 goto L1 L4: L5: - r9 = None - return r9 + r11 = None + return r11 def g(x): x :: object r0 :: short_int @@ -946,44 +956,48 @@ def f(a, b): b :: object r0 :: short_int r1 :: object - r2 :: short_int - r3 :: bool - r4, r5 :: object - x, r6 :: int - r7, y, r8 :: bool - r9 :: short_int - r10 :: bool - r11 :: None + r2 :: ptr + r3 :: native_int + r4 :: short_int + r5 :: bool + r6, r7 :: object + x, r8 :: int + r9, y, r10 :: bool + r11 :: short_int + r12 :: bool + r13 :: None L0: r0 = 0 r1 = PyObject_GetIter(b) L1: - r2 = len a :: list - r3 = r0 < r2 :: signed - if r3 goto L2 else goto L7 :: bool + r2 = get_element_ptr a ob_size :: PyVarObject + r3 = load_mem r2 :: native_int* + r4 = r3 << 1 + r5 = r0 < r4 :: signed + if r5 goto L2 else goto L7 :: bool L2: - r4 = PyIter_Next(r1) - if is_error(r4) goto L7 else goto L3 + r6 = PyIter_Next(r1) + if is_error(r6) goto L7 else goto L3 L3: - r5 = a[r0] :: unsafe list - r6 = unbox(int, r5) - x = r6 - r7 = unbox(bool, r4) - y = r7 - r8 = bool b :: object - if r8 goto L4 else goto L5 :: bool + r7 = a[r0] :: unsafe list + r8 = unbox(int, r7) + x = r8 + r9 = unbox(bool, r6) + y = r9 + r10 = bool b :: object + if r10 goto L4 else goto L5 :: bool L4: x = 2 L5: L6: - r9 = r0 + 2 - r0 = r9 + r11 = r0 + 2 + r0 = r11 goto L1 L7: - r10 = CPy_NoErrOccured() + r12 = CPy_NoErrOccured() L8: - r11 = None - return r11 + r13 = None + return r13 def g(a, b): a :: object b :: list @@ -991,14 +1005,16 @@ def g(a, b): r1, r2 :: short_int z :: int r3 :: object - r4 :: short_int - r5, r6, r7, x :: bool - r8 :: object - y, r9 :: int - r10 :: bool - r11, r12 :: short_int - r13 :: bool - r14 :: None + r4 :: ptr + r5 :: native_int + r6 :: short_int + r7, r8, r9, x :: bool + r10 :: object + y, r11 :: int + r12 :: bool + r13, r14 :: short_int + r15 :: bool + r16 :: None L0: r0 = PyObject_GetIter(a) r1 = 0 @@ -1008,30 +1024,32 @@ L1: r3 = PyIter_Next(r0) if is_error(r3) goto L6 else goto L2 L2: - r4 = len b :: list - r5 = r1 < r4 :: signed - if r5 goto L3 else goto L6 :: bool + r4 = get_element_ptr b ob_size :: PyVarObject + r5 = load_mem r4 :: native_int* + r6 = r5 << 1 + r7 = r1 < r6 :: signed + if r7 goto L3 else goto L6 :: bool L3: - r6 = r2 < 10 :: signed - if r6 goto L4 else goto L6 :: bool + r8 = r2 < 10 :: signed + if r8 goto L4 else goto L6 :: bool L4: - r7 = unbox(bool, r3) - x = r7 - r8 = b[r1] :: unsafe list - r9 = unbox(int, r8) - y = r9 - r10 = False - x = r10 + r9 = unbox(bool, r3) + x = r9 + r10 = b[r1] :: unsafe list + r11 = unbox(int, r10) + y = r11 + r12 = False + x = r12 L5: - r11 = r1 + 2 - r1 = r11 - r12 = r2 + 2 - r2 = r12 - z = r12 + r13 = r1 + 2 + r1 = r13 + r14 = r2 + 2 + r2 = r14 + z = r14 goto L1 L6: - r13 = CPy_NoErrOccured() + r15 = CPy_NoErrOccured() L7: - r14 = None - return r14 + r16 = None + return r16 diff --git a/mypyc/test/test_emitfunc.py b/mypyc/test/test_emitfunc.py index a2e821e9148b..a1954eda7348 100644 --- a/mypyc/test/test_emitfunc.py +++ b/mypyc/test/test_emitfunc.py @@ -15,7 +15,7 @@ from mypyc.ir.rtypes import ( RTuple, RInstance, int_rprimitive, bool_rprimitive, list_rprimitive, dict_rprimitive, object_rprimitive, c_int_rprimitive, short_int_rprimitive, int32_rprimitive, - int64_rprimitive, StructInfo, RStruct + int64_rprimitive, RStruct, pointer_rprimitive ) from mypyc.ir.func_ir import FuncIR, FuncDecl, RuntimeArg, FuncSignature from mypyc.ir.class_ir import ClassIR @@ -25,7 +25,7 @@ from mypyc.primitives.registry import binary_ops, c_binary_ops from mypyc.primitives.misc_ops import none_object_op, true_op, false_op from mypyc.primitives.list_ops import ( - list_len_op, list_get_item_op, list_set_item_op, new_list_op, list_append_op + list_get_item_op, list_set_item_op, new_list_op, list_append_op ) from mypyc.primitives.dict_ops import ( dict_new_op, dict_update_op, dict_get_item_op, dict_set_item_op @@ -33,7 +33,6 @@ from mypyc.primitives.int_ops import int_neg_op from mypyc.subtype import is_subtype from mypyc.namegen import NameGenerator -from mypyc.common import IS_32_BIT_PLATFORM class TestFunctionEmitterVisitor(unittest.TestCase): @@ -54,6 +53,7 @@ def setUp(self) -> None: self.i32_1 = self.env.add_local(Var('i32_1'), int32_rprimitive) self.i64 = self.env.add_local(Var('i64'), int64_rprimitive) self.i64_1 = self.env.add_local(Var('i64_1'), int64_rprimitive) + self.ptr = self.env.add_local(Var('ptr'), pointer_rprimitive) self.t = self.env.add_local(Var('t'), RTuple([int_rprimitive, bool_rprimitive])) self.tt = self.env.add_local( Var('tt'), @@ -117,13 +117,6 @@ def test_int_neg(self) -> None: int_neg_op.steals, int_neg_op.error_kind, 55), "cpy_r_r0 = CPyTagged_Negate(cpy_r_m);") - def test_list_len(self) -> None: - self.assert_emit(PrimitiveOp([self.l], list_len_op, 55), - """Py_ssize_t __tmp1; - __tmp1 = PyList_GET_SIZE(cpy_r_l); - cpy_r_r0 = CPyTagged_ShortFromSsize_t(__tmp1); - """) - def test_branch(self) -> None: self.assert_emit(Branch(self.b, BasicBlock(8), BasicBlock(9), Branch.BOOL_EXPR), """if (cpy_r_b) { @@ -275,23 +268,18 @@ def test_binary_int_op(self) -> None: """cpy_r_r04 = (uint64_t)cpy_r_i64 < (uint64_t)cpy_r_i64_1;""") def test_load_mem(self) -> None: - if IS_32_BIT_PLATFORM: - self.assert_emit(LoadMem(bool_rprimitive, self.i32), - """cpy_r_r0 = *(char *)cpy_r_i32;""") - else: - self.assert_emit(LoadMem(bool_rprimitive, self.i64), - """cpy_r_r0 = *(char *)cpy_r_i64;""") + self.assert_emit(LoadMem(bool_rprimitive, self.ptr), + """cpy_r_r0 = *(char *)cpy_r_ptr;""") def test_get_element_ptr(self) -> None: - info = StructInfo("Foo", ["b", "i32", "i64"], [bool_rprimitive, - int32_rprimitive, int64_rprimitive]) - r = RStruct(info) + r = RStruct("Foo", ["b", "i32", "i64"], [bool_rprimitive, + int32_rprimitive, int64_rprimitive]) self.assert_emit(GetElementPtr(self.o, r, "b"), - """cpy_r_r0 = &cpy_r_o.b;""") + """cpy_r_r0 = (CPyPtr)&((Foo *)cpy_r_o)->b;""") self.assert_emit(GetElementPtr(self.o, r, "i32"), - """cpy_r_r00 = &cpy_r_o.i32;""") + """cpy_r_r00 = (CPyPtr)&((Foo *)cpy_r_o)->i32;""") self.assert_emit(GetElementPtr(self.o, r, "i64"), - """cpy_r_r01 = &cpy_r_o.i64;""") + """cpy_r_r01 = (CPyPtr)&((Foo *)cpy_r_o)->i64;""") def assert_emit(self, op: Op, expected: str) -> None: self.emitter.fragments = [] diff --git a/mypyc/test/test_struct.py b/mypyc/test/test_struct.py index 0478b891063b..0617f83bbb38 100644 --- a/mypyc/test/test_struct.py +++ b/mypyc/test/test_struct.py @@ -1,7 +1,7 @@ import unittest from mypyc.ir.rtypes import ( - RStruct, bool_rprimitive, int64_rprimitive, int32_rprimitive, object_rprimitive, StructInfo, + RStruct, bool_rprimitive, int64_rprimitive, int32_rprimitive, object_rprimitive, int_rprimitive ) from mypyc.rt_subtype import is_runtime_subtype @@ -10,93 +10,106 @@ class TestStruct(unittest.TestCase): def test_struct_offsets(self) -> None: # test per-member alignment - info = StructInfo("", [], [bool_rprimitive, int32_rprimitive, int64_rprimitive]) - r = RStruct(info) + r = RStruct("", [], [bool_rprimitive, int32_rprimitive, int64_rprimitive]) assert r.size == 16 assert r.offsets == [0, 4, 8] # test final alignment - info1 = StructInfo("", [], [bool_rprimitive, bool_rprimitive]) - r1 = RStruct(info1) + r1 = RStruct("", [], [bool_rprimitive, bool_rprimitive]) assert r1.size == 2 assert r1.offsets == [0, 1] - info2 = StructInfo("", [], [int32_rprimitive, bool_rprimitive]) - r2 = RStruct(info2) - info3 = StructInfo("", [], [int64_rprimitive, bool_rprimitive]) - r3 = RStruct(info3) + r2 = RStruct("", [], [int32_rprimitive, bool_rprimitive]) + r3 = RStruct("", [], [int64_rprimitive, bool_rprimitive]) assert r2.offsets == [0, 4] assert r3.offsets == [0, 8] assert r2.size == 8 assert r3.size == 16 - info4 = StructInfo("", [], [bool_rprimitive, bool_rprimitive, + r4 = RStruct("", [], [bool_rprimitive, bool_rprimitive, bool_rprimitive, int32_rprimitive]) - r4 = RStruct(info4) assert r4.size == 8 assert r4.offsets == [0, 1, 2, 4] # test nested struct - info5 = StructInfo("", [], [bool_rprimitive, r]) - r5 = RStruct(info5) + r5 = RStruct("", [], [bool_rprimitive, r]) assert r5.offsets == [0, 8] assert r5.size == 24 - info6 = StructInfo("", [], [int32_rprimitive, r5]) - r6 = RStruct(info6) + r6 = RStruct("", [], [int32_rprimitive, r5]) assert r6.offsets == [0, 8] assert r6.size == 32 # test nested struct with alignment less than 8 - info7 = StructInfo("", [], [bool_rprimitive, r4]) - r7 = RStruct(info7) + r7 = RStruct("", [], [bool_rprimitive, r4]) assert r7.offsets == [0, 4] assert r7.size == 12 def test_struct_str(self) -> None: - info = StructInfo("Foo", ["a", "b"], + r = RStruct("Foo", ["a", "b"], [bool_rprimitive, object_rprimitive]) - r = RStruct(info) assert str(r) == "Foo{a:bool, b:object}" assert repr(r) == ", " \ "b:}>" - info1 = StructInfo("Bar", ["c"], [int32_rprimitive]) - r1 = RStruct(info1) + r1 = RStruct("Bar", ["c"], [int32_rprimitive]) assert str(r1) == "Bar{c:int32}" assert repr(r1) == "}>" - info2 = StructInfo("Baz", [], []) - r2 = RStruct(info2) + r2 = RStruct("Baz", [], []) assert str(r2) == "Baz{}" assert repr(r2) == "" def test_runtime_subtype(self) -> None: # right type to check with - info = StructInfo("Foo", ["a", "b"], + r = RStruct("Foo", ["a", "b"], [bool_rprimitive, int_rprimitive]) - r = RStruct(info) - # using the same StructInfo - r1 = RStruct(info) + # using the exact same fields + r1 = RStruct("Foo", ["a", "b"], + [bool_rprimitive, int_rprimitive]) # names different - info2 = StructInfo("Bar", ["c", "b"], + r2 = RStruct("Bar", ["c", "b"], [bool_rprimitive, int_rprimitive]) - r2 = RStruct(info2) # name different - info3 = StructInfo("Baz", ["a", "b"], + r3 = RStruct("Baz", ["a", "b"], [bool_rprimitive, int_rprimitive]) - r3 = RStruct(info3) # type different - info4 = StructInfo("FooBar", ["a", "b"], + r4 = RStruct("FooBar", ["a", "b"], [bool_rprimitive, int32_rprimitive]) - r4 = RStruct(info4) # number of types different - info5 = StructInfo("FooBarBaz", ["a", "b", "c"], + r5 = RStruct("FooBarBaz", ["a", "b", "c"], [bool_rprimitive, int_rprimitive, bool_rprimitive]) - r5 = RStruct(info5) assert is_runtime_subtype(r1, r) is True assert is_runtime_subtype(r2, r) is False assert is_runtime_subtype(r3, r) is False assert is_runtime_subtype(r4, r) is False assert is_runtime_subtype(r5, r) is False + + def test_eq_and_hash(self) -> None: + r = RStruct("Foo", ["a", "b"], + [bool_rprimitive, int_rprimitive]) + + # using the exact same fields + r1 = RStruct("Foo", ["a", "b"], + [bool_rprimitive, int_rprimitive]) + assert hash(r) == hash(r1) + assert r == r1 + + # different name + r2 = RStruct("Foq", ["a", "b"], + [bool_rprimitive, int_rprimitive]) + assert hash(r) != hash(r2) + assert r != r2 + + # different names + r3 = RStruct("Foo", ["a", "c"], + [bool_rprimitive, int_rprimitive]) + assert hash(r) != hash(r3) + assert r != r3 + + # different type + r4 = RStruct("Foo", ["a", "b"], + [bool_rprimitive, int_rprimitive, bool_rprimitive]) + assert hash(r) != hash(r4) + assert r != r4 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy