From a0a0ada29905b786faf05770b13501fd6a20c891 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Fri, 22 Mar 2024 10:01:25 +0000 Subject: [PATCH] [mypyc] Refactor: use primitive op for initializing list item (#17056) Add a new primitive op for initializing list items. Also add support for primitive ops that steal operands (reference counting wise). This will also remove most instances of `WORD_SIZE` in irbuild tests, which were a bit painful, since running tests with `--update-data` removed these and they had to be manually added back for 32-bit tests to pass. --- mypyc/ir/ops.py | 8 + mypyc/ir/pprint.py | 5 +- mypyc/irbuild/ll_builder.py | 14 +- mypyc/lower/int_ops.py | 14 +- mypyc/lower/list_ops.py | 34 ++++ mypyc/lower/registry.py | 7 +- mypyc/primitives/misc_ops.py | 22 ++- mypyc/primitives/registry.py | 35 ++++ mypyc/test-data/irbuild-any.test | 7 +- mypyc/test-data/irbuild-basic.test | 182 ++++++++++---------- mypyc/test-data/irbuild-classes.test | 2 +- mypyc/test-data/irbuild-dict.test | 2 +- mypyc/test-data/irbuild-generics.test | 2 +- mypyc/test-data/irbuild-i64.test | 4 +- mypyc/test-data/irbuild-lists.test | 32 ++-- mypyc/test-data/irbuild-set.test | 216 ++++++++++++------------ mypyc/test-data/irbuild-statements.test | 67 ++++---- mypyc/test-data/irbuild-str.test | 21 ++- mypyc/test-data/irbuild-tuple.test | 103 ++++++----- mypyc/test-data/lowering-list.test | 33 ++++ mypyc/test-data/refcount.test | 11 +- mypyc/test/test_lowering.py | 4 +- 22 files changed, 463 insertions(+), 362 deletions(-) create mode 100644 mypyc/lower/list_ops.py create mode 100644 mypyc/test-data/lowering-list.test diff --git a/mypyc/ir/ops.py b/mypyc/ir/ops.py index 3acfb0933e5a..7df4347171da 100644 --- a/mypyc/ir/ops.py +++ b/mypyc/ir/ops.py @@ -644,6 +644,14 @@ def __init__(self, args: list[Value], desc: PrimitiveDescription, line: int = -1 def sources(self) -> list[Value]: return self.args + def stolen(self) -> list[Value]: + steals = self.desc.steals + if isinstance(steals, list): + assert len(steals) == len(self.args) + return [arg for arg, steal in zip(self.args, steals) if steal] + else: + return [] if not steals else self.sources() + def accept(self, visitor: OpVisitor[T]) -> T: return visitor.visit_primitive_op(self) diff --git a/mypyc/ir/pprint.py b/mypyc/ir/pprint.py index 2ca6a47921fc..59ee994f012d 100644 --- a/mypyc/ir/pprint.py +++ b/mypyc/ir/pprint.py @@ -232,7 +232,10 @@ def visit_primitive_op(self, op: PrimitiveOp) -> str: type_arg_index += 1 args_str = ", ".join(args) - return self.format("%r = %s %s", op, op.desc.name, args_str) + if op.is_void: + return self.format("%s %s", op.desc.name, args_str) + else: + return self.format("%r = %s %s", op, op.desc.name, args_str) def visit_truncate(self, op: Truncate) -> str: return self.format("%r = truncate %r: %t to %t", op, op.src, op.src_type, op.type) diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index e989471ceb59..134265852b2f 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -67,7 +67,6 @@ PrimitiveOp, RaiseStandardError, Register, - SetMem, Truncate, TupleGet, TupleSet, @@ -165,7 +164,7 @@ uint8_overflow, ) from mypyc.primitives.list_ops import list_build_op, list_extend_op, new_list_op -from mypyc.primitives.misc_ops import bool_op, fast_isinstance_op, none_object_op +from mypyc.primitives.misc_ops import bool_op, buf_init_item, fast_isinstance_op, none_object_op from mypyc.primitives.registry import ( ERR_NEG_INT, CFunctionDescription, @@ -1627,14 +1626,9 @@ def new_list_op(self, values: list[Value], line: int) -> Value: ob_item_ptr = self.add(GetElementPtr(result_list, PyListObject, "ob_item", line)) ob_item_base = self.add(LoadMem(pointer_rprimitive, ob_item_ptr, line)) for i in range(len(values)): - if i == 0: - item_address = ob_item_base - else: - offset = Integer(PLATFORM_SIZE * i, c_pyssize_t_rprimitive, line) - item_address = self.add( - IntOp(pointer_rprimitive, ob_item_base, offset, IntOp.ADD, line) - ) - self.add(SetMem(object_rprimitive, item_address, args[i], line)) + self.primitive_op( + buf_init_item, [ob_item_base, Integer(i, c_pyssize_t_rprimitive), args[i]], line + ) self.add(KeepAlive([result_list])) return result_list diff --git a/mypyc/lower/int_ops.py b/mypyc/lower/int_ops.py index 90a3253ba093..adfb4c21e2de 100644 --- a/mypyc/lower/int_ops.py +++ b/mypyc/lower/int_ops.py @@ -7,7 +7,7 @@ from mypyc.ir.ops import Assign, BasicBlock, Branch, ComparisonOp, Register, Value from mypyc.ir.rtypes import bool_rprimitive, is_short_int_rprimitive from mypyc.irbuild.ll_builder import LowLevelIRBuilder -from mypyc.lower.registry import lower_binary_op +from mypyc.lower.registry import lower_primitive_op from mypyc.primitives.int_ops import int_equal_, int_less_than_ from mypyc.primitives.registry import CFunctionDescription @@ -83,31 +83,31 @@ def compare_tagged(self: LowLevelIRBuilder, lhs: Value, rhs: Value, op: str, lin return result -@lower_binary_op("int_eq") +@lower_primitive_op("int_eq") def lower_int_eq(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value: return compare_tagged(builder, args[0], args[1], "==", line) -@lower_binary_op("int_ne") +@lower_primitive_op("int_ne") def lower_int_ne(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value: return compare_tagged(builder, args[0], args[1], "!=", line) -@lower_binary_op("int_lt") +@lower_primitive_op("int_lt") def lower_int_lt(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value: return compare_tagged(builder, args[0], args[1], "<", line) -@lower_binary_op("int_le") +@lower_primitive_op("int_le") def lower_int_le(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value: return compare_tagged(builder, args[0], args[1], "<=", line) -@lower_binary_op("int_gt") +@lower_primitive_op("int_gt") def lower_int_gt(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value: return compare_tagged(builder, args[0], args[1], ">", line) -@lower_binary_op("int_ge") +@lower_primitive_op("int_ge") def lower_int_ge(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value: return compare_tagged(builder, args[0], args[1], ">=", line) diff --git a/mypyc/lower/list_ops.py b/mypyc/lower/list_ops.py new file mode 100644 index 000000000000..f4619e07dc7e --- /dev/null +++ b/mypyc/lower/list_ops.py @@ -0,0 +1,34 @@ +from __future__ import annotations + +from mypyc.common import PLATFORM_SIZE +from mypyc.ir.ops import Integer, IntOp, SetMem, Value +from mypyc.ir.rtypes import c_pyssize_t_rprimitive, object_rprimitive, pointer_rprimitive +from mypyc.irbuild.ll_builder import LowLevelIRBuilder +from mypyc.lower.registry import lower_primitive_op + + +@lower_primitive_op("buf_init_item") +def buf_init_item(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value: + """Initialize an item in a buffer of "PyObject *" values at given index. + + This can be used to initialize the data buffer of a freshly allocated list + object. + """ + base = args[0] + index_value = args[1] + value = args[2] + assert isinstance(index_value, Integer) + index = index_value.numeric_value() + if index == 0: + ptr = base + else: + ptr = builder.add( + IntOp( + pointer_rprimitive, + base, + Integer(index * PLATFORM_SIZE, c_pyssize_t_rprimitive), + IntOp.ADD, + line, + ) + ) + return builder.add(SetMem(object_rprimitive, ptr, value, line)) diff --git a/mypyc/lower/registry.py b/mypyc/lower/registry.py index cc53eb93f4dd..d1599dc98cf4 100644 --- a/mypyc/lower/registry.py +++ b/mypyc/lower/registry.py @@ -11,8 +11,8 @@ lowering_registry: Final[dict[str, LowerFunc]] = {} -def lower_binary_op(name: str) -> Callable[[LowerFunc], LowerFunc]: - """Register a handler that generates low-level IR for a primitive binary op.""" +def lower_primitive_op(name: str) -> Callable[[LowerFunc], LowerFunc]: + """Register a handler that generates low-level IR for a primitive op.""" def wrapper(f: LowerFunc) -> LowerFunc: assert name not in lowering_registry @@ -23,4 +23,5 @@ def wrapper(f: LowerFunc) -> LowerFunc: # Import various modules that set up global state. -import mypyc.lower.int_ops # noqa: F401 +import mypyc.lower.int_ops +import mypyc.lower.list_ops # noqa: F401 diff --git a/mypyc/primitives/misc_ops.py b/mypyc/primitives/misc_ops.py index 5a8cc111ebc2..87d009f7bbab 100644 --- a/mypyc/primitives/misc_ops.py +++ b/mypyc/primitives/misc_ops.py @@ -13,9 +13,17 @@ int_rprimitive, object_pointer_rprimitive, object_rprimitive, + pointer_rprimitive, str_rprimitive, + void_rtype, +) +from mypyc.primitives.registry import ( + ERR_NEG_INT, + custom_op, + custom_primitive_op, + function_op, + load_address_op, ) -from mypyc.primitives.registry import ERR_NEG_INT, custom_op, function_op, load_address_op # Get the 'bool' type object. load_address_op(name="builtins.bool", type=object_rprimitive, src="PyBool_Type") @@ -232,10 +240,20 @@ ) -# register an implementation for a singledispatch function +# Register an implementation for a singledispatch function register_function = custom_op( arg_types=[object_rprimitive, object_rprimitive, object_rprimitive], return_type=object_rprimitive, c_function_name="CPySingledispatch_RegisterFunction", error_kind=ERR_MAGIC, ) + + +# Initialize a PyObject * item in a memory buffer (steal the value) +buf_init_item = custom_primitive_op( + name="buf_init_item", + arg_types=[pointer_rprimitive, c_pyssize_t_rprimitive, object_rprimitive], + return_type=void_rtype, + error_kind=ERR_NEVER, + steals=[False, False, True], +) diff --git a/mypyc/primitives/registry.py b/mypyc/primitives/registry.py index d4768b4df532..1472885a4829 100644 --- a/mypyc/primitives/registry.py +++ b/mypyc/primitives/registry.py @@ -267,6 +267,41 @@ def custom_op( ) +def custom_primitive_op( + name: str, + arg_types: list[RType], + return_type: RType, + error_kind: int, + c_function_name: str | None = None, + var_arg_type: RType | None = None, + truncated_type: RType | None = None, + ordering: list[int] | None = None, + extra_int_constants: list[tuple[int, RType]] | None = None, + steals: StealsDescription = False, + is_borrowed: bool = False, +) -> PrimitiveDescription: + """Define a primitive op that can't be automatically generated based on the AST. + + Most arguments are similar to method_op(). + """ + if extra_int_constants is None: + extra_int_constants = [] + return PrimitiveDescription( + name=name, + arg_types=arg_types, + return_type=return_type, + var_arg_type=var_arg_type, + truncated_type=truncated_type, + c_function_name=c_function_name, + error_kind=error_kind, + steals=steals, + is_borrowed=is_borrowed, + ordering=ordering, + extra_int_constants=extra_int_constants, + priority=0, + ) + + def unary_op( name: str, arg_type: RType, diff --git a/mypyc/test-data/irbuild-any.test b/mypyc/test-data/irbuild-any.test index 98f3dae9ee88..dd1931ba40f3 100644 --- a/mypyc/test-data/irbuild-any.test +++ b/mypyc/test-data/irbuild-any.test @@ -106,7 +106,7 @@ def f2(a, n, l): r9, r10 :: bit r11 :: list r12 :: object - r13, r14, r15 :: ptr + r13, r14 :: ptr L0: r0 = box(int, n) r1 = PyObject_GetItem(a, r0) @@ -123,9 +123,8 @@ L0: r12 = box(int, n) r13 = get_element_ptr r11 ob_item :: PyListObject r14 = load_mem r13 :: ptr* - set_mem r14, a :: builtins.object* - r15 = r14 + WORD_SIZE*1 - set_mem r15, r12 :: builtins.object* + buf_init_item r14, 0, a + buf_init_item r14, 1, r12 keep_alive r11 return 1 def f3(a, n): diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index 164fc213a8a2..766e584d4149 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -771,7 +771,7 @@ L0: r2 = object 1 r3 = get_element_ptr r1 ob_item :: PyListObject r4 = load_mem r3 :: ptr* - set_mem r4, r2 :: builtins.object* + buf_init_item r4, 0, r2 keep_alive r1 r5 = g(r1) r6 = box(None, 1) @@ -801,7 +801,7 @@ L0: r2 = PyList_New(1) r3 = get_element_ptr r2 ob_item :: PyListObject r4 = load_mem r3 :: ptr* - set_mem r4, y :: builtins.object* + buf_init_item r4, 0, y keep_alive r2 a = r2 r5 = (2, 4) @@ -1676,7 +1676,7 @@ L0: r5 = object 1 r6 = get_element_ptr r4 ob_item :: PyListObject r7 = load_mem r6 :: ptr* - set_mem r7, r5 :: builtins.object* + buf_init_item r7, 0, r5 keep_alive r4 r8 = box(tuple[int, int], r0) r9 = CPyList_Extend(r4, r8) @@ -1849,20 +1849,20 @@ def f() -> List[int]: def f(): r0, r1 :: list r2, r3, r4 :: object - r5, r6, r7, r8 :: ptr - r9 :: short_int - r10 :: ptr - r11 :: native_int - r12 :: short_int - r13 :: bit - r14 :: object - r15, x :: int - r16, r17 :: bit - r18 :: int - r19 :: object - r20 :: i32 - r21 :: bit - r22 :: short_int + r5, r6 :: ptr + r7 :: short_int + r8 :: ptr + r9 :: native_int + r10 :: short_int + r11 :: bit + r12 :: object + r13, x :: int + r14, r15 :: bit + r16 :: int + r17 :: object + r18 :: i32 + r19 :: bit + r20 :: short_int L0: r0 = PyList_New(0) r1 = PyList_New(3) @@ -1871,41 +1871,39 @@ L0: r4 = object 3 r5 = get_element_ptr r1 ob_item :: PyListObject r6 = load_mem r5 :: ptr* - set_mem r6, r2 :: builtins.object* - r7 = r6 + WORD_SIZE*1 - set_mem r7, r3 :: builtins.object* - r8 = r6 + WORD_SIZE*2 - set_mem r8, r4 :: builtins.object* + buf_init_item r6, 0, r2 + buf_init_item r6, 1, r3 + buf_init_item r6, 2, r4 keep_alive r1 - r9 = 0 + r7 = 0 L1: - r10 = get_element_ptr r1 ob_size :: PyVarObject - r11 = load_mem r10 :: native_int* + r8 = get_element_ptr r1 ob_size :: PyVarObject + r9 = load_mem r8 :: native_int* keep_alive r1 - r12 = r11 << 1 - r13 = int_lt r9, r12 - if r13 goto L2 else goto L8 :: bool + r10 = r9 << 1 + r11 = int_lt r7, r10 + if r11 goto L2 else goto L8 :: bool L2: - r14 = CPyList_GetItemUnsafe(r1, r9) - r15 = unbox(int, r14) - x = r15 - r16 = int_ne x, 4 - if r16 goto L4 else goto L3 :: bool + r12 = CPyList_GetItemUnsafe(r1, r7) + r13 = unbox(int, r12) + x = r13 + r14 = int_ne x, 4 + if r14 goto L4 else goto L3 :: bool L3: goto L7 L4: - r17 = int_ne x, 6 - if r17 goto L6 else goto L5 :: bool + r15 = int_ne x, 6 + if r15 goto L6 else goto L5 :: bool L5: goto L7 L6: - r18 = CPyTagged_Multiply(x, x) - r19 = box(int, r18) - r20 = PyList_Append(r0, r19) - r21 = r20 >= 0 :: signed + r16 = CPyTagged_Multiply(x, x) + r17 = box(int, r16) + r18 = PyList_Append(r0, r17) + r19 = r18 >= 0 :: signed L7: - r22 = r9 + 2 - r9 = r22 + r20 = r7 + 2 + r7 = r20 goto L1 L8: return r0 @@ -1919,20 +1917,20 @@ def f(): r0 :: dict r1 :: list r2, r3, r4 :: object - r5, r6, r7, r8 :: ptr - r9 :: short_int - r10 :: ptr - r11 :: native_int - r12 :: short_int - r13 :: bit - r14 :: object - r15, x :: int - r16, r17 :: bit - r18 :: int - r19, r20 :: object - r21 :: i32 - r22 :: bit - r23 :: short_int + r5, r6 :: ptr + r7 :: short_int + r8 :: ptr + r9 :: native_int + r10 :: short_int + r11 :: bit + r12 :: object + r13, x :: int + r14, r15 :: bit + r16 :: int + r17, r18 :: object + r19 :: i32 + r20 :: bit + r21 :: short_int L0: r0 = PyDict_New() r1 = PyList_New(3) @@ -1941,42 +1939,40 @@ L0: r4 = object 3 r5 = get_element_ptr r1 ob_item :: PyListObject r6 = load_mem r5 :: ptr* - set_mem r6, r2 :: builtins.object* - r7 = r6 + WORD_SIZE*1 - set_mem r7, r3 :: builtins.object* - r8 = r6 + WORD_SIZE*2 - set_mem r8, r4 :: builtins.object* + buf_init_item r6, 0, r2 + buf_init_item r6, 1, r3 + buf_init_item r6, 2, r4 keep_alive r1 - r9 = 0 + r7 = 0 L1: - r10 = get_element_ptr r1 ob_size :: PyVarObject - r11 = load_mem r10 :: native_int* + r8 = get_element_ptr r1 ob_size :: PyVarObject + r9 = load_mem r8 :: native_int* keep_alive r1 - r12 = r11 << 1 - r13 = int_lt r9, r12 - if r13 goto L2 else goto L8 :: bool + r10 = r9 << 1 + r11 = int_lt r7, r10 + if r11 goto L2 else goto L8 :: bool L2: - r14 = CPyList_GetItemUnsafe(r1, r9) - r15 = unbox(int, r14) - x = r15 - r16 = int_ne x, 4 - if r16 goto L4 else goto L3 :: bool + r12 = CPyList_GetItemUnsafe(r1, r7) + r13 = unbox(int, r12) + x = r13 + r14 = int_ne x, 4 + if r14 goto L4 else goto L3 :: bool L3: goto L7 L4: - r17 = int_ne x, 6 - if r17 goto L6 else goto L5 :: bool + r15 = int_ne x, 6 + if r15 goto L6 else goto L5 :: bool L5: goto L7 L6: - r18 = CPyTagged_Multiply(x, x) - r19 = box(int, x) - r20 = box(int, r18) - r21 = CPyDict_SetItem(r0, r19, r20) - r22 = r21 >= 0 :: signed + r16 = CPyTagged_Multiply(x, x) + r17 = box(int, x) + r18 = box(int, r16) + r19 = CPyDict_SetItem(r0, r17, r18) + r20 = r19 >= 0 :: signed L7: - r23 = r9 + 2 - r9 = r23 + r21 = r7 + 2 + r7 = r21 goto L1 L8: return r0 @@ -2208,11 +2204,11 @@ def __top_level__(): r59 :: bit r60 :: list r61, r62, r63 :: object - r64, r65, r66, r67 :: ptr - r68 :: dict - r69 :: str - r70 :: i32 - r71 :: bit + r64, r65 :: ptr + r66 :: dict + r67 :: str + r68 :: i32 + r69 :: bit L0: r0 = builtins :: module r1 = load_address _Py_NoneStruct @@ -2285,16 +2281,14 @@ L2: r63 = object 3 r64 = get_element_ptr r60 ob_item :: PyListObject r65 = load_mem r64 :: ptr* - set_mem r65, r61 :: builtins.object* - r66 = r65 + WORD_SIZE*1 - set_mem r66, r62 :: builtins.object* - r67 = r65 + WORD_SIZE*2 - set_mem r67, r63 :: builtins.object* + buf_init_item r65, 0, r61 + buf_init_item r65, 1, r62 + buf_init_item r65, 2, r63 keep_alive r60 - r68 = __main__.globals :: static - r69 = 'y' - r70 = CPyDict_SetItem(r68, r69, r60) - r71 = r70 >= 0 :: signed + r66 = __main__.globals :: static + r67 = 'y' + r68 = CPyDict_SetItem(r66, r67, r60) + r69 = r68 >= 0 :: signed return 1 [case testChainedConditional] diff --git a/mypyc/test-data/irbuild-classes.test b/mypyc/test-data/irbuild-classes.test index 8c4743c6a47f..cbed51ebcfb0 100644 --- a/mypyc/test-data/irbuild-classes.test +++ b/mypyc/test-data/irbuild-classes.test @@ -53,7 +53,7 @@ L0: r2 = PyList_New(1) r3 = get_element_ptr r2 ob_item :: PyListObject r4 = load_mem r3 :: ptr* - set_mem r4, c :: builtins.object* + buf_init_item r4, 0, c keep_alive r2 a = r2 r5 = CPyList_GetItemShort(a, 0) diff --git a/mypyc/test-data/irbuild-dict.test b/mypyc/test-data/irbuild-dict.test index 1a84f3fe3098..9445219a08ce 100644 --- a/mypyc/test-data/irbuild-dict.test +++ b/mypyc/test-data/irbuild-dict.test @@ -551,7 +551,7 @@ L2: r4 = object 1 r5 = get_element_ptr r3 ob_item :: PyListObject r6 = load_mem r5 :: ptr* - set_mem r6, r4 :: builtins.object* + buf_init_item r6, 0, r4 keep_alive r3 r7 = CPyDict_SetDefault(d, r2, r3) return r7 diff --git a/mypyc/test-data/irbuild-generics.test b/mypyc/test-data/irbuild-generics.test index 35920889e596..50f6ed6cda1e 100644 --- a/mypyc/test-data/irbuild-generics.test +++ b/mypyc/test-data/irbuild-generics.test @@ -23,7 +23,7 @@ L0: r1 = PyList_New(1) r2 = get_element_ptr r1 ob_item :: PyListObject r3 = load_mem r2 :: ptr* - set_mem r3, r0 :: builtins.object* + buf_init_item r3, 0, r0 keep_alive r1 return r1 def h(x, y): diff --git a/mypyc/test-data/irbuild-i64.test b/mypyc/test-data/irbuild-i64.test index 07f549c9fcc2..ad2a97e6eeff 100644 --- a/mypyc/test-data/irbuild-i64.test +++ b/mypyc/test-data/irbuild-i64.test @@ -1150,7 +1150,7 @@ L0: r1 = PyList_New(1) r2 = get_element_ptr r1 ob_item :: PyListObject r3 = load_mem r2 :: ptr* - set_mem r3, r0 :: builtins.object* + buf_init_item r3, 0, r0 keep_alive r1 a = r1 r4 = CPyList_GetItemInt64Borrow(a, n) @@ -1260,7 +1260,7 @@ L0: r1 = box(i64, n) r2 = get_element_ptr r0 ob_item :: PyListObject r3 = load_mem r2 :: ptr* - set_mem r3, r1 :: builtins.object* + buf_init_item r3, 0, r1 keep_alive r0 r4 = n <= 4611686018427387903 :: signed if r4 goto L1 else goto L2 :: bool diff --git a/mypyc/test-data/irbuild-lists.test b/mypyc/test-data/irbuild-lists.test index ced4646922a3..66aa1dc748be 100644 --- a/mypyc/test-data/irbuild-lists.test +++ b/mypyc/test-data/irbuild-lists.test @@ -108,7 +108,7 @@ def f() -> None: def f(): r0 :: list r1, r2 :: object - r3, r4, r5 :: ptr + r3, r4 :: ptr x :: list L0: r0 = PyList_New(2) @@ -116,9 +116,8 @@ L0: r2 = object 2 r3 = get_element_ptr r0 ob_item :: PyListObject r4 = load_mem r3 :: ptr* - set_mem r4, r1 :: builtins.object* - r5 = r4 + WORD_SIZE*1 - set_mem r5, r2 :: builtins.object* + buf_init_item r4, 0, r1 + buf_init_item r4, 1, r2 keep_alive r0 x = r0 return 1 @@ -165,7 +164,7 @@ L0: r2 = object 4 r3 = get_element_ptr r1 ob_item :: PyListObject r4 = load_mem r3 :: ptr* - set_mem r4, r2 :: builtins.object* + buf_init_item r4, 0, r2 keep_alive r1 r5 = CPySequence_RMultiply(6, r1) b = r5 @@ -253,25 +252,24 @@ def f(x: List[int], y: List[int]) -> List[int]: def f(x, y): x, y, r0 :: list r1, r2 :: object - r3, r4, r5 :: ptr - r6, r7, r8 :: object - r9 :: i32 - r10 :: bit + r3, r4 :: ptr + r5, r6, r7 :: object + r8 :: i32 + r9 :: bit L0: r0 = PyList_New(2) r1 = object 1 r2 = object 2 r3 = get_element_ptr r0 ob_item :: PyListObject r4 = load_mem r3 :: ptr* - set_mem r4, r1 :: builtins.object* - r5 = r4 + WORD_SIZE*1 - set_mem r5, r2 :: builtins.object* + buf_init_item r4, 0, r1 + buf_init_item r4, 1, r2 keep_alive r0 - r6 = CPyList_Extend(r0, x) - r7 = CPyList_Extend(r0, y) - r8 = object 3 - r9 = PyList_Append(r0, r8) - r10 = r9 >= 0 :: signed + r5 = CPyList_Extend(r0, x) + r6 = CPyList_Extend(r0, y) + r7 = object 3 + r8 = PyList_Append(r0, r7) + r9 = r8 >= 0 :: signed return r0 [case testListIn] diff --git a/mypyc/test-data/irbuild-set.test b/mypyc/test-data/irbuild-set.test index 51feab332593..ea900f2e4789 100644 --- a/mypyc/test-data/irbuild-set.test +++ b/mypyc/test-data/irbuild-set.test @@ -79,20 +79,20 @@ L0: def test1(): r0 :: list r1, r2, r3 :: object - r4, r5, r6, r7 :: ptr + r4, r5 :: ptr tmp_list :: list - r8 :: set - r9 :: short_int - r10 :: ptr - r11 :: native_int - r12 :: short_int - r13 :: bit - r14 :: object - r15, x, r16 :: int - r17 :: object - r18 :: i32 - r19 :: bit - r20 :: short_int + r6 :: set + r7 :: short_int + r8 :: ptr + r9 :: native_int + r10 :: short_int + r11 :: bit + r12 :: object + r13, x, r14 :: int + r15 :: object + r16 :: i32 + r17 :: bit + r18 :: short_int a :: set L0: r0 = PyList_New(3) @@ -101,36 +101,34 @@ L0: r3 = object 5 r4 = get_element_ptr r0 ob_item :: PyListObject r5 = load_mem r4 :: ptr* - set_mem r5, r1 :: builtins.object* - r6 = r5 + WORD_SIZE*1 - set_mem r6, r2 :: builtins.object* - r7 = r5 + WORD_SIZE*2 - set_mem r7, r3 :: builtins.object* + buf_init_item r5, 0, r1 + buf_init_item r5, 1, r2 + buf_init_item r5, 2, r3 keep_alive r0 tmp_list = r0 - r8 = PySet_New(0) - r9 = 0 + r6 = PySet_New(0) + r7 = 0 L1: - r10 = get_element_ptr tmp_list ob_size :: PyVarObject - r11 = load_mem r10 :: native_int* + r8 = get_element_ptr tmp_list ob_size :: PyVarObject + r9 = load_mem r8 :: native_int* keep_alive tmp_list - r12 = r11 << 1 - r13 = int_lt r9, r12 - if r13 goto L2 else goto L4 :: bool + r10 = r9 << 1 + r11 = int_lt r7, r10 + if r11 goto L2 else goto L4 :: bool L2: - r14 = CPyList_GetItemUnsafe(tmp_list, r9) - r15 = unbox(int, r14) - x = r15 - r16 = f(x) - r17 = box(int, r16) - r18 = PySet_Add(r8, r17) - r19 = r18 >= 0 :: signed + r12 = CPyList_GetItemUnsafe(tmp_list, r7) + r13 = unbox(int, r12) + x = r13 + r14 = f(x) + r15 = box(int, r14) + r16 = PySet_Add(r6, r15) + r17 = r16 >= 0 :: signed L3: - r20 = r9 + 2 - r9 = r20 + r18 = r7 + 2 + r7 = r18 goto L1 L4: - a = r8 + a = r6 return 1 def test2(): r0, tmp_tuple :: tuple[int, int, int] @@ -312,33 +310,33 @@ L0: def test(): r0 :: list r1, r2, r3, r4, r5 :: object - r6, r7, r8, r9, r10, r11 :: ptr + r6, r7 :: ptr tmp_list :: list - r12 :: set - r13, r14 :: list - r15 :: short_int - r16 :: ptr - r17 :: native_int - r18 :: short_int - r19 :: bit + r8 :: set + r9, r10 :: list + r11 :: short_int + r12 :: ptr + r13 :: native_int + r14 :: short_int + r15 :: bit + r16 :: object + r17, z :: int + r18 :: bit + r19 :: int r20 :: object - r21, z :: int + r21 :: i32 r22 :: bit - r23 :: int - r24 :: object - r25 :: i32 - r26 :: bit - r27 :: short_int - r28, r29, r30 :: object - r31, y, r32 :: int - r33 :: object - r34 :: i32 - r35, r36 :: bit - r37, r38, r39 :: object - r40, x, r41 :: int - r42 :: object - r43 :: i32 - r44, r45 :: bit + r23 :: short_int + r24, r25, r26 :: object + r27, y, r28 :: int + r29 :: object + r30 :: i32 + r31, r32 :: bit + r33, r34, r35 :: object + r36, x, r37 :: int + r38 :: object + r39 :: i32 + r40, r41 :: bit a :: set L0: r0 = PyList_New(5) @@ -349,81 +347,77 @@ L0: r5 = object 5 r6 = get_element_ptr r0 ob_item :: PyListObject r7 = load_mem r6 :: ptr* - set_mem r7, r1 :: builtins.object* - r8 = r7 + WORD_SIZE*1 - set_mem r8, r2 :: builtins.object* - r9 = r7 + WORD_SIZE*2 - set_mem r9, r3 :: builtins.object* - r10 = r7 + WORD_SIZE*3 - set_mem r10, r4 :: builtins.object* - r11 = r7 + WORD_SIZE*4 - set_mem r11, r5 :: builtins.object* + buf_init_item r7, 0, r1 + buf_init_item r7, 1, r2 + buf_init_item r7, 2, r3 + buf_init_item r7, 3, r4 + buf_init_item r7, 4, r5 keep_alive r0 tmp_list = r0 - r12 = PySet_New(0) - r13 = PyList_New(0) - r14 = PyList_New(0) - r15 = 0 + r8 = PySet_New(0) + r9 = PyList_New(0) + r10 = PyList_New(0) + r11 = 0 L1: - r16 = get_element_ptr tmp_list ob_size :: PyVarObject - r17 = load_mem r16 :: native_int* + r12 = get_element_ptr tmp_list ob_size :: PyVarObject + r13 = load_mem r12 :: native_int* keep_alive tmp_list - r18 = r17 << 1 - r19 = int_lt r15, r18 - if r19 goto L2 else goto L6 :: bool + r14 = r13 << 1 + r15 = int_lt r11, r14 + if r15 goto L2 else goto L6 :: bool L2: - r20 = CPyList_GetItemUnsafe(tmp_list, r15) - r21 = unbox(int, r20) - z = r21 - r22 = int_lt z, 8 - if r22 goto L4 else goto L3 :: bool + r16 = CPyList_GetItemUnsafe(tmp_list, r11) + r17 = unbox(int, r16) + z = r17 + r18 = int_lt z, 8 + if r18 goto L4 else goto L3 :: bool L3: goto L5 L4: - r23 = f1(z) - r24 = box(int, r23) - r25 = PyList_Append(r14, r24) - r26 = r25 >= 0 :: signed + r19 = f1(z) + r20 = box(int, r19) + r21 = PyList_Append(r10, r20) + r22 = r21 >= 0 :: signed L5: - r27 = r15 + 2 - r15 = r27 + r23 = r11 + 2 + r11 = r23 goto L1 L6: - r28 = PyObject_GetIter(r14) - r29 = PyObject_GetIter(r28) + r24 = PyObject_GetIter(r10) + r25 = PyObject_GetIter(r24) L7: - r30 = PyIter_Next(r29) - if is_error(r30) goto L10 else goto L8 + r26 = PyIter_Next(r25) + if is_error(r26) goto L10 else goto L8 L8: - r31 = unbox(int, r30) - y = r31 - r32 = f2(y) - r33 = box(int, r32) - r34 = PyList_Append(r13, r33) - r35 = r34 >= 0 :: signed + r27 = unbox(int, r26) + y = r27 + r28 = f2(y) + r29 = box(int, r28) + r30 = PyList_Append(r9, r29) + r31 = r30 >= 0 :: signed L9: goto L7 L10: - r36 = CPy_NoErrOccured() + r32 = CPy_NoErrOccured() L11: - r37 = PyObject_GetIter(r13) - r38 = PyObject_GetIter(r37) + r33 = PyObject_GetIter(r9) + r34 = PyObject_GetIter(r33) L12: - r39 = PyIter_Next(r38) - if is_error(r39) goto L15 else goto L13 + r35 = PyIter_Next(r34) + if is_error(r35) goto L15 else goto L13 L13: - r40 = unbox(int, r39) - x = r40 - r41 = f3(x) - r42 = box(int, r41) - r43 = PySet_Add(r12, r42) - r44 = r43 >= 0 :: signed + r36 = unbox(int, r35) + x = r36 + r37 = f3(x) + r38 = box(int, r37) + r39 = PySet_Add(r8, r38) + r40 = r39 >= 0 :: signed L14: goto L12 L15: - r45 = CPy_NoErrOccured() + r41 = CPy_NoErrOccured() L16: - a = r12 + a = r8 return 1 [case testSetSize] diff --git a/mypyc/test-data/irbuild-statements.test b/mypyc/test-data/irbuild-statements.test index ed97c4cd4138..628d692c85c1 100644 --- a/mypyc/test-data/irbuild-statements.test +++ b/mypyc/test-data/irbuild-statements.test @@ -688,40 +688,39 @@ def delListMultiple() -> None: def delList(): r0 :: list r1, r2 :: object - r3, r4, r5 :: ptr + r3, r4 :: ptr l :: list - r6 :: object - r7 :: i32 - r8 :: bit + r5 :: object + r6 :: i32 + r7 :: bit L0: r0 = PyList_New(2) r1 = object 1 r2 = object 2 r3 = get_element_ptr r0 ob_item :: PyListObject r4 = load_mem r3 :: ptr* - set_mem r4, r1 :: builtins.object* - r5 = r4 + WORD_SIZE*1 - set_mem r5, r2 :: builtins.object* + buf_init_item r4, 0, r1 + buf_init_item r4, 1, r2 keep_alive r0 l = r0 - r6 = object 1 - r7 = PyObject_DelItem(l, r6) - r8 = r7 >= 0 :: signed + r5 = object 1 + r6 = PyObject_DelItem(l, r5) + r7 = r6 >= 0 :: signed return 1 def delListMultiple(): r0 :: list r1, r2, r3, r4, r5, r6, r7 :: object - r8, r9, r10, r11, r12, r13, r14, r15 :: ptr + r8, r9 :: ptr l :: list + r10 :: object + r11 :: i32 + r12 :: bit + r13 :: object + r14 :: i32 + r15 :: bit r16 :: object r17 :: i32 r18 :: bit - r19 :: object - r20 :: i32 - r21 :: bit - r22 :: object - r23 :: i32 - r24 :: bit L0: r0 = PyList_New(7) r1 = object 1 @@ -733,30 +732,24 @@ L0: r7 = object 7 r8 = get_element_ptr r0 ob_item :: PyListObject r9 = load_mem r8 :: ptr* - set_mem r9, r1 :: builtins.object* - r10 = r9 + WORD_SIZE*1 - set_mem r10, r2 :: builtins.object* - r11 = r9 + WORD_SIZE*2 - set_mem r11, r3 :: builtins.object* - r12 = r9 + WORD_SIZE*3 - set_mem r12, r4 :: builtins.object* - r13 = r9 + WORD_SIZE*4 - set_mem r13, r5 :: builtins.object* - r14 = r9 + WORD_SIZE*5 - set_mem r14, r6 :: builtins.object* - r15 = r9 + WORD_SIZE*6 - set_mem r15, r7 :: builtins.object* + buf_init_item r9, 0, r1 + buf_init_item r9, 1, r2 + buf_init_item r9, 2, r3 + buf_init_item r9, 3, r4 + buf_init_item r9, 4, r5 + buf_init_item r9, 5, r6 + buf_init_item r9, 6, r7 keep_alive r0 l = r0 - r16 = object 1 + r10 = object 1 + r11 = PyObject_DelItem(l, r10) + r12 = r11 >= 0 :: signed + r13 = object 2 + r14 = PyObject_DelItem(l, r13) + r15 = r14 >= 0 :: signed + r16 = object 3 r17 = PyObject_DelItem(l, r16) r18 = r17 >= 0 :: signed - r19 = object 2 - r20 = PyObject_DelItem(l, r19) - r21 = r20 >= 0 :: signed - r22 = object 3 - r23 = PyObject_DelItem(l, r22) - r24 = r23 >= 0 :: signed return 1 [case testDelDict] diff --git a/mypyc/test-data/irbuild-str.test b/mypyc/test-data/irbuild-str.test index 9851e0f4fb24..dfaa50520364 100644 --- a/mypyc/test-data/irbuild-str.test +++ b/mypyc/test-data/irbuild-str.test @@ -203,8 +203,8 @@ def f(var, num): r12 :: object r13 :: str r14 :: list - r15, r16, r17 :: ptr - r18, s2, r19, s3, r20, s4 :: str + r15, r16 :: ptr + r17, s2, r18, s3, r19, s4 :: str L0: r0 = "Hi! I'm " r1 = '. I am ' @@ -224,16 +224,15 @@ L0: r14 = PyList_New(2) r15 = get_element_ptr r14 ob_item :: PyListObject r16 = load_mem r15 :: ptr* - set_mem r16, r6 :: builtins.object* - r17 = r16 + WORD_SIZE*1 - set_mem r17, r13 :: builtins.object* + buf_init_item r16, 0, r6 + buf_init_item r16, 1, r13 keep_alive r14 - r18 = PyUnicode_Join(r5, r14) - s2 = r18 - r19 = '' - s3 = r19 - r20 = 'abc' - s4 = r20 + r17 = PyUnicode_Join(r5, r14) + s2 = r17 + r18 = '' + s3 = r18 + r19 = 'abc' + s4 = r19 return 1 [case testStringFormattingCStyle] diff --git a/mypyc/test-data/irbuild-tuple.test b/mypyc/test-data/irbuild-tuple.test index 342bb19b5360..0a26d8aa1d3d 100644 --- a/mypyc/test-data/irbuild-tuple.test +++ b/mypyc/test-data/irbuild-tuple.test @@ -101,28 +101,27 @@ def f(x, y): x, y :: object r0 :: list r1, r2 :: object - r3, r4, r5 :: ptr - r6, r7, r8 :: object - r9 :: i32 - r10 :: bit - r11 :: tuple + r3, r4 :: ptr + r5, r6, r7 :: object + r8 :: i32 + r9 :: bit + r10 :: tuple L0: r0 = PyList_New(2) r1 = object 1 r2 = object 2 r3 = get_element_ptr r0 ob_item :: PyListObject r4 = load_mem r3 :: ptr* - set_mem r4, r1 :: builtins.object* - r5 = r4 + WORD_SIZE*1 - set_mem r5, r2 :: builtins.object* + buf_init_item r4, 0, r1 + buf_init_item r4, 1, r2 keep_alive r0 - r6 = CPyList_Extend(r0, x) - r7 = CPyList_Extend(r0, y) - r8 = object 3 - r9 = PyList_Append(r0, r8) - r10 = r9 >= 0 :: signed - r11 = PyList_AsTuple(r0) - return r11 + r5 = CPyList_Extend(r0, x) + r6 = CPyList_Extend(r0, y) + r7 = object 3 + r8 = PyList_Append(r0, r7) + r9 = r8 >= 0 :: signed + r10 = PyList_AsTuple(r0) + return r10 [case testTupleFor] from typing import Tuple, List @@ -238,22 +237,22 @@ L0: def test(): r0 :: list r1, r2, r3 :: object - r4, r5, r6, r7 :: ptr + r4, r5 :: ptr source :: list - r8 :: ptr - r9 :: native_int - r10 :: tuple - r11 :: short_int - r12 :: ptr - r13 :: native_int - r14 :: short_int - r15 :: bit - r16 :: object - r17, x :: int - r18 :: bool - r19 :: object - r20 :: bit - r21 :: short_int + r6 :: ptr + r7 :: native_int + r8 :: tuple + r9 :: short_int + r10 :: ptr + r11 :: native_int + r12 :: short_int + r13 :: bit + r14 :: object + r15, x :: int + r16 :: bool + r17 :: object + r18 :: bit + r19 :: short_int a :: tuple L0: r0 = PyList_New(3) @@ -262,38 +261,36 @@ L0: r3 = object 3 r4 = get_element_ptr r0 ob_item :: PyListObject r5 = load_mem r4 :: ptr* - set_mem r5, r1 :: builtins.object* - r6 = r5 + WORD_SIZE*1 - set_mem r6, r2 :: builtins.object* - r7 = r5 + WORD_SIZE*2 - set_mem r7, r3 :: builtins.object* + buf_init_item r5, 0, r1 + buf_init_item r5, 1, r2 + buf_init_item r5, 2, r3 keep_alive r0 source = r0 - r8 = get_element_ptr source ob_size :: PyVarObject - r9 = load_mem r8 :: native_int* + r6 = get_element_ptr source ob_size :: PyVarObject + r7 = load_mem r6 :: native_int* keep_alive source - r10 = PyTuple_New(r9) - r11 = 0 + r8 = PyTuple_New(r7) + r9 = 0 L1: - r12 = get_element_ptr source ob_size :: PyVarObject - r13 = load_mem r12 :: native_int* + r10 = get_element_ptr source ob_size :: PyVarObject + r11 = load_mem r10 :: native_int* keep_alive source - r14 = r13 << 1 - r15 = int_lt r11, r14 - if r15 goto L2 else goto L4 :: bool + r12 = r11 << 1 + r13 = int_lt r9, r12 + if r13 goto L2 else goto L4 :: bool L2: - r16 = CPyList_GetItemUnsafe(source, r11) - r17 = unbox(int, r16) - x = r17 - r18 = f(x) - r19 = box(bool, r18) - r20 = CPySequenceTuple_SetItemUnsafe(r10, r11, r19) + r14 = CPyList_GetItemUnsafe(source, r9) + r15 = unbox(int, r14) + x = r15 + r16 = f(x) + r17 = box(bool, r16) + r18 = CPySequenceTuple_SetItemUnsafe(r8, r9, r17) L3: - r21 = r11 + 2 - r11 = r21 + r19 = r9 + 2 + r9 = r19 goto L1 L4: - a = r10 + a = r8 return 1 [case testTupleBuiltFromStr] diff --git a/mypyc/test-data/lowering-list.test b/mypyc/test-data/lowering-list.test new file mode 100644 index 000000000000..c8438d869970 --- /dev/null +++ b/mypyc/test-data/lowering-list.test @@ -0,0 +1,33 @@ +[case testLowerListDisplay] +def f() -> None: + a = [4, 6, 7] +[out] +def f(): + r0 :: list + r1, r2, r3 :: object + r4, r5, r6, r7 :: ptr + a :: list + r8 :: None +L0: + r0 = PyList_New(3) + if is_error(r0) goto L2 (error at f:2) else goto L1 +L1: + r1 = object 4 + r2 = object 6 + r3 = object 7 + r4 = get_element_ptr r0 ob_item :: PyListObject + r5 = load_mem r4 :: ptr* + inc_ref r1 + set_mem r5, r1 :: builtins.object* + inc_ref r2 + r6 = r5 + WORD_SIZE*1 + set_mem r6, r2 :: builtins.object* + inc_ref r3 + r7 = r5 + WORD_SIZE*2 + set_mem r7, r3 :: builtins.object* + a = r0 + dec_ref a + return 1 +L2: + r8 = :: None + return r8 diff --git a/mypyc/test-data/refcount.test b/mypyc/test-data/refcount.test index 3021381abded..b8d598e3b533 100644 --- a/mypyc/test-data/refcount.test +++ b/mypyc/test-data/refcount.test @@ -498,7 +498,7 @@ def f() -> int: def f(): r0 :: list r1, r2 :: object - r3, r4, r5 :: ptr + r3, r4 :: ptr a :: list L0: r0 = PyList_New(2) @@ -507,10 +507,9 @@ L0: r3 = get_element_ptr r0 ob_item :: PyListObject r4 = load_mem r3 :: ptr* inc_ref r1 - set_mem r4, r1 :: builtins.object* - r5 = r4 + WORD_SIZE*1 + buf_init_item r4, 0, r1 inc_ref r2 - set_mem r5, r2 :: builtins.object* + buf_init_item r4, 1, r2 a = r0 dec_ref a return 0 @@ -586,7 +585,7 @@ L0: r1 = PyList_New(1) r2 = get_element_ptr r1 ob_item :: PyListObject r3 = load_mem r2 :: ptr* - set_mem r3, r0 :: builtins.object* + buf_init_item r3, 0, r0 a = r1 r4 = CPyList_GetItemShort(a, 0) dec_ref a @@ -1266,7 +1265,7 @@ L0: r1 = PyList_New(1) r2 = get_element_ptr r1 ob_item :: PyListObject r3 = load_mem r2 :: ptr* - set_mem r3, r0 :: builtins.object* + buf_init_item r3, 0, r0 a = r1 r4 = CPyList_GetItemShortBorrow(a, 0) r5 = borrow cast(__main__.C, r4) diff --git a/mypyc/test/test_lowering.py b/mypyc/test/test_lowering.py index e32dba2e1021..50a9a7390855 100644 --- a/mypyc/test/test_lowering.py +++ b/mypyc/test/test_lowering.py @@ -16,6 +16,7 @@ assert_test_output, build_ir_for_single_file, remove_comment_lines, + replace_word_size, use_custom_builtins, ) from mypyc.transform.exceptions import insert_exception_handling @@ -26,12 +27,13 @@ class TestLowering(MypycDataSuite): - files = ["lowering-int.test"] + files = ["lowering-int.test", "lowering-list.test"] base_path = test_temp_dir def run_case(self, testcase: DataDrivenTestCase) -> None: with use_custom_builtins(os.path.join(self.data_prefix, ICODE_GEN_BUILTINS), testcase): expected_output = remove_comment_lines(testcase.output) + expected_output = replace_word_size(expected_output) try: ir = build_ir_for_single_file(testcase.input) except CompileError as e: