From afdd9d5b2bb8a9ed9819571b266903396f47c5d9 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Tue, 19 Mar 2024 17:08:51 +0000 Subject: [PATCH] [mypyc] Implement lowering for remaining tagged integer comparisons (#17040) Support lowering of tagged integer `<`, `<=`, `>` and `>=` operations. Previously we had separate code paths for integer comparisons in values vs conditions. Unify these and remove the duplicate code path. The different code paths produced subtly different code, but now they are identical. The generated code is now sometimes slightly more verbose in the slow path (big integer). I may look into simplifying it in a follow-up PR. This also makes the output of many irbuild test cases significantly more compact. Follow-up to #17027. Work on mypyc/mypyc#854. --- mypyc/ir/pprint.py | 2 +- mypyc/irbuild/ast_helpers.py | 9 +- mypyc/irbuild/builder.py | 3 - mypyc/irbuild/expression.py | 6 - mypyc/irbuild/function.py | 5 +- mypyc/irbuild/ll_builder.py | 94 +---- mypyc/lower/int_ops.py | 20 + mypyc/primitives/int_ops.py | 4 + mypyc/test-data/analysis.test | 205 +++------ mypyc/test-data/exceptions.test | 58 +-- mypyc/test-data/irbuild-basic.test | 435 +++++--------------- mypyc/test-data/irbuild-bool.test | 56 +-- mypyc/test-data/irbuild-dunders.test | 20 +- mypyc/test-data/irbuild-int.test | 51 +-- mypyc/test-data/irbuild-lists.test | 13 +- mypyc/test-data/irbuild-set.test | 126 +++--- mypyc/test-data/irbuild-singledispatch.test | 2 +- mypyc/test-data/irbuild-statements.test | 140 ++----- mypyc/test-data/irbuild-tuple.test | 8 +- mypyc/test-data/lowering-int.test | 273 +++++++++++- mypyc/test-data/refcount.test | 60 +-- 21 files changed, 622 insertions(+), 968 deletions(-) diff --git a/mypyc/ir/pprint.py b/mypyc/ir/pprint.py index 8d6723917ea0..2ca6a47921fc 100644 --- a/mypyc/ir/pprint.py +++ b/mypyc/ir/pprint.py @@ -232,7 +232,7 @@ 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) + 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/ast_helpers.py b/mypyc/irbuild/ast_helpers.py index 8490eaa03477..bc976647675d 100644 --- a/mypyc/irbuild/ast_helpers.py +++ b/mypyc/irbuild/ast_helpers.py @@ -93,12 +93,9 @@ def maybe_process_conditional_comparison( self.add_bool_branch(reg, true, false) else: # "left op right" for two tagged integers - if op in ("==", "!="): - reg = self.builder.binary_op(left, right, op, e.line) - self.flush_keep_alives() - self.add_bool_branch(reg, true, false) - else: - self.builder.compare_tagged_condition(left, right, op, true, false, e.line) + reg = self.builder.binary_op(left, right, op, e.line) + self.flush_keep_alives() + self.add_bool_branch(reg, true, false) return True diff --git a/mypyc/irbuild/builder.py b/mypyc/irbuild/builder.py index 52891d68e3b2..cca771e82c83 100644 --- a/mypyc/irbuild/builder.py +++ b/mypyc/irbuild/builder.py @@ -378,9 +378,6 @@ def call_c(self, desc: CFunctionDescription, args: list[Value], line: int) -> Va def int_op(self, type: RType, lhs: Value, rhs: Value, op: int, line: int) -> Value: return self.builder.int_op(type, lhs, rhs, op, line) - def compare_tagged(self, lhs: Value, rhs: Value, op: str, line: int) -> Value: - return self.builder.compare_tagged(lhs, rhs, op, line) - def compare_tuples(self, lhs: Value, rhs: Value, op: str, line: int) -> Value: return self.builder.compare_tuples(lhs, rhs, op, line) diff --git a/mypyc/irbuild/expression.py b/mypyc/irbuild/expression.py index 021b7a1dbe90..ba62d71d0ad3 100644 --- a/mypyc/irbuild/expression.py +++ b/mypyc/irbuild/expression.py @@ -814,12 +814,6 @@ def translate_is_none(builder: IRBuilder, expr: Expression, negated: bool) -> Va def transform_basic_comparison( builder: IRBuilder, op: str, left: Value, right: Value, line: int ) -> Value: - if ( - is_int_rprimitive(left.type) - and is_int_rprimitive(right.type) - and op in int_comparison_op_mapping - ): - return builder.compare_tagged(left, right, op, line) if is_fixed_width_rtype(left.type) and op in int_comparison_op_mapping: if right.type == left.type: if left.type.is_signed: diff --git a/mypyc/irbuild/function.py b/mypyc/irbuild/function.py index b1785f40550e..c985e88b0e0c 100644 --- a/mypyc/irbuild/function.py +++ b/mypyc/irbuild/function.py @@ -889,9 +889,8 @@ def gen_native_func_call_and_return(fdef: FuncDef) -> None: call_impl, next_impl = BasicBlock(), BasicBlock() current_id = builder.load_int(i) - builder.builder.compare_tagged_condition( - passed_id, current_id, "==", call_impl, next_impl, line - ) + cond = builder.binary_op(passed_id, current_id, "==", line) + builder.add_bool_branch(cond, call_impl, next_impl) # Call the registered implementation builder.activate_block(call_impl) diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index f9bacb43bc3e..548b391030fe 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -1315,13 +1315,6 @@ def binary_op(self, lreg: Value, rreg: Value, op: str, line: int) -> Value: return self.compare_strings(lreg, rreg, op, line) if is_bytes_rprimitive(ltype) and is_bytes_rprimitive(rtype) and op in ("==", "!="): return self.compare_bytes(lreg, rreg, op, line) - if ( - is_tagged(ltype) - and is_tagged(rtype) - and op in int_comparison_op_mapping - and op not in ("==", "!=") - ): - return self.compare_tagged(lreg, rreg, op, line) if is_bool_rprimitive(ltype) and is_bool_rprimitive(rtype) and op in BOOL_BINARY_OPS: if op in ComparisonOp.signed_ops: return self.bool_comparison_op(lreg, rreg, op, line) @@ -1384,16 +1377,6 @@ def binary_op(self, lreg: Value, rreg: Value, op: str, line: int) -> Value: if is_fixed_width_rtype(lreg.type): return self.comparison_op(lreg, rreg, op_id, line) - # Mixed int comparisons - if op in ("==", "!="): - pass # TODO: Do we need anything here? - elif op in op in int_comparison_op_mapping: - if is_tagged(ltype) and is_subtype(rtype, ltype): - rreg = self.coerce(rreg, short_int_rprimitive, line) - return self.compare_tagged(lreg, rreg, op, line) - if is_tagged(rtype) and is_subtype(ltype, rtype): - lreg = self.coerce(lreg, short_int_rprimitive, line) - return self.compare_tagged(lreg, rreg, op, line) if is_float_rprimitive(ltype) or is_float_rprimitive(rtype): if isinstance(lreg, Integer): lreg = Float(float(lreg.numeric_value())) @@ -1445,18 +1428,16 @@ def compare_tagged(self, lhs: Value, rhs: Value, op: str, line: int) -> Value: op_type, c_func_desc, negate_result, swap_op = int_comparison_op_mapping[op] result = Register(bool_rprimitive) short_int_block, int_block, out = BasicBlock(), BasicBlock(), BasicBlock() - check_lhs = self.check_tagged_short_int(lhs, line) + check_lhs = self.check_tagged_short_int(lhs, line, negated=True) if op in ("==", "!="): - check = check_lhs + self.add(Branch(check_lhs, int_block, short_int_block, Branch.BOOL)) else: # for non-equality logical ops (less/greater than, etc.), need to check both sides - check_rhs = self.check_tagged_short_int(rhs, line) - check = self.int_op(bit_rprimitive, check_lhs, check_rhs, IntOp.AND, line) - self.add(Branch(check, short_int_block, int_block, Branch.BOOL)) - self.activate_block(short_int_block) - eq = self.comparison_op(lhs, rhs, op_type, line) - self.add(Assign(result, eq, line)) - self.goto(out) + short_lhs = BasicBlock() + self.add(Branch(check_lhs, int_block, short_lhs, Branch.BOOL)) + self.activate_block(short_lhs) + check_rhs = self.check_tagged_short_int(rhs, line, negated=True) + self.add(Branch(check_rhs, int_block, short_int_block, Branch.BOOL)) self.activate_block(int_block) if swap_op: args = [rhs, lhs] @@ -1469,62 +1450,12 @@ def compare_tagged(self, lhs: Value, rhs: Value, op: str, line: int) -> Value: else: call_result = call self.add(Assign(result, call_result, line)) - self.goto_and_activate(out) - return result - - def compare_tagged_condition( - self, lhs: Value, rhs: Value, op: str, true: BasicBlock, false: BasicBlock, line: int - ) -> None: - """Compare two tagged integers using given operator (conditional context). - - Assume lhs and rhs are tagged integers. - - Args: - lhs: Left operand - rhs: Right operand - op: Operation, one of '==', '!=', '<', '<=', '>', '<=' - true: Branch target if comparison is true - false: Branch target if comparison is false - """ - is_eq = op in ("==", "!=") - if (is_short_int_rprimitive(lhs.type) and is_short_int_rprimitive(rhs.type)) or ( - is_eq and (is_short_int_rprimitive(lhs.type) or is_short_int_rprimitive(rhs.type)) - ): - # We can skip the tag check - check = self.comparison_op(lhs, rhs, int_comparison_op_mapping[op][0], line) - self.flush_keep_alives() - self.add(Branch(check, true, false, Branch.BOOL)) - return - op_type, c_func_desc, negate_result, swap_op = int_comparison_op_mapping[op] - int_block, short_int_block = BasicBlock(), BasicBlock() - check_lhs = self.check_tagged_short_int(lhs, line, negated=True) - if is_eq or is_short_int_rprimitive(rhs.type): - self.flush_keep_alives() - self.add(Branch(check_lhs, int_block, short_int_block, Branch.BOOL)) - else: - # For non-equality logical ops (less/greater than, etc.), need to check both sides - rhs_block = BasicBlock() - self.add(Branch(check_lhs, int_block, rhs_block, Branch.BOOL)) - self.activate_block(rhs_block) - check_rhs = self.check_tagged_short_int(rhs, line, negated=True) - self.flush_keep_alives() - self.add(Branch(check_rhs, int_block, short_int_block, Branch.BOOL)) - # Arbitrary integers (slow path) - self.activate_block(int_block) - if swap_op: - args = [rhs, lhs] - else: - args = [lhs, rhs] - call = self.call_c(c_func_desc, args, line) - if negate_result: - self.add(Branch(call, false, true, Branch.BOOL)) - else: - self.flush_keep_alives() - self.add(Branch(call, true, false, Branch.BOOL)) - # Short integers (fast path) + self.goto(out) self.activate_block(short_int_block) eq = self.comparison_op(lhs, rhs, op_type, line) - self.add(Branch(eq, true, false, Branch.BOOL)) + self.add(Assign(result, eq, line)) + self.goto_and_activate(out) + return result def compare_strings(self, lhs: Value, rhs: Value, op: str, line: int) -> Value: """Compare two strings""" @@ -2309,7 +2240,8 @@ def builtin_len(self, val: Value, line: int, use_pyssize_t: bool = False) -> Val length = self.gen_method_call(val, "__len__", [], int_rprimitive, line) length = self.coerce(length, int_rprimitive, line) ok, fail = BasicBlock(), BasicBlock() - self.compare_tagged_condition(length, Integer(0), ">=", ok, fail, line) + cond = self.binary_op(length, Integer(0), ">=", line) + self.add_bool_branch(cond, ok, fail) self.activate_block(fail) self.add( RaiseStandardError( diff --git a/mypyc/lower/int_ops.py b/mypyc/lower/int_ops.py index 40fba7af4f4d..5255a64b647d 100644 --- a/mypyc/lower/int_ops.py +++ b/mypyc/lower/int_ops.py @@ -13,3 +13,23 @@ def lower_int_eq(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Va @lower_binary_op("int_ne") def lower_int_ne(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value: return builder.compare_tagged(args[0], args[1], "!=", line) + + +@lower_binary_op("int_lt") +def lower_int_lt(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value: + return builder.compare_tagged(args[0], args[1], "<", line) + + +@lower_binary_op("int_le") +def lower_int_le(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value: + return builder.compare_tagged(args[0], args[1], "<=", line) + + +@lower_binary_op("int_gt") +def lower_int_gt(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value: + return builder.compare_tagged(args[0], args[1], ">", line) + + +@lower_binary_op("int_ge") +def lower_int_ge(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value: + return builder.compare_tagged(args[0], args[1], ">=", line) diff --git a/mypyc/primitives/int_ops.py b/mypyc/primitives/int_ops.py index 4103fe349a74..029d71606886 100644 --- a/mypyc/primitives/int_ops.py +++ b/mypyc/primitives/int_ops.py @@ -122,6 +122,10 @@ def int_binary_primitive( int_eq = int_binary_primitive(op="==", primitive_name="int_eq", return_type=bit_rprimitive) int_ne = int_binary_primitive(op="!=", primitive_name="int_ne", return_type=bit_rprimitive) +int_lt = int_binary_primitive(op="<", primitive_name="int_lt", return_type=bit_rprimitive) +int_le = int_binary_primitive(op="<=", primitive_name="int_le", return_type=bit_rprimitive) +int_gt = int_binary_primitive(op=">", primitive_name="int_gt", return_type=bit_rprimitive) +int_ge = int_binary_primitive(op=">=", primitive_name="int_ge", return_type=bit_rprimitive) def int_binary_op( diff --git a/mypyc/test-data/analysis.test b/mypyc/test-data/analysis.test index 8e067aed4d79..35677b8ea56d 100644 --- a/mypyc/test-data/analysis.test +++ b/mypyc/test-data/analysis.test @@ -148,40 +148,27 @@ def f(n: int) -> None: [out] def f(n): n :: int - r0 :: native_int - r1, r2, r3 :: bit - r4, m :: int + r0 :: bit + r1, m :: int L0: L1: - r0 = n & 1 - r1 = r0 != 0 - if r1 goto L2 else goto L3 :: bool + r0 = int_lt n, 10 + if r0 goto L2 else goto L3 :: bool L2: - r2 = CPyTagged_IsLt_(n, 10) - if r2 goto L4 else goto L5 :: bool -L3: - r3 = n < 10 :: signed - if r3 goto L4 else goto L5 :: bool -L4: - r4 = CPyTagged_Add(n, 2) - n = r4 + r1 = CPyTagged_Add(n, 2) + n = r1 m = n goto L1 -L5: +L3: return 1 (0, 0) {n} {n} (1, 0) {n} {n} (1, 1) {n} {n} -(1, 2) {n} {n} (2, 0) {n} {n} (2, 1) {n} {n} +(2, 2) {n} {m, n} +(2, 3) {m, n} {m, n} (3, 0) {n} {n} -(3, 1) {n} {n} -(4, 0) {n} {n} -(4, 1) {n} {n} -(4, 2) {n} {m, n} -(4, 3) {m, n} {m, n} -(5, 0) {n} {n} [case testMultiPass_Liveness] def f(n: int) -> None: @@ -195,67 +182,40 @@ def f(n: int) -> None: [out] def f(n): n, x, y :: int - r0 :: native_int - r1, r2, r3 :: bit - r4 :: native_int - r5, r6, r7 :: bit + r0, r1 :: bit L0: x = 2 y = 2 L1: - r0 = n & 1 - r1 = r0 != 0 - if r1 goto L2 else goto L3 :: bool + r0 = int_lt n, 2 + if r0 goto L2 else goto L6 :: bool L2: - r2 = CPyTagged_IsLt_(n, 2) - if r2 goto L4 else goto L10 :: bool + n = y L3: - r3 = n < 2 :: signed - if r3 goto L4 else goto L10 :: bool + r1 = int_lt n, 4 + if r1 goto L4 else goto L5 :: bool L4: - n = y -L5: - r4 = n & 1 - r5 = r4 != 0 - if r5 goto L6 else goto L7 :: bool -L6: - r6 = CPyTagged_IsLt_(n, 4) - if r6 goto L8 else goto L9 :: bool -L7: - r7 = n < 4 :: signed - if r7 goto L8 else goto L9 :: bool -L8: n = 2 n = x - goto L5 -L9: + goto L3 +L5: goto L1 -L10: +L6: return 1 (0, 0) {n} {n, x} (0, 1) {n, x} {n, x, y} (0, 2) {n, x, y} {n, x, y} -(1, 0) {n, x, y} {n, r0, x, y} -(1, 1) {n, r0, x, y} {n, r1, x, y} -(1, 2) {n, r1, x, y} {n, x, y} -(2, 0) {n, x, y} {r2, x, y} -(2, 1) {r2, x, y} {x, y} -(3, 0) {n, x, y} {r3, x, y} -(3, 1) {r3, x, y} {x, y} -(4, 0) {x, y} {n, x, y} -(4, 1) {n, x, y} {n, x, y} -(5, 0) {n, x, y} {n, r4, x, y} -(5, 1) {n, r4, x, y} {n, r5, x, y} -(5, 2) {n, r5, x, y} {n, x, y} -(6, 0) {n, x, y} {n, r6, x, y} -(6, 1) {n, r6, x, y} {n, x, y} -(7, 0) {n, x, y} {n, r7, x, y} -(7, 1) {n, r7, x, y} {n, x, y} -(8, 0) {x, y} {x, y} -(8, 1) {x, y} {n, x, y} -(8, 2) {n, x, y} {n, x, y} -(9, 0) {n, x, y} {n, x, y} -(10, 0) {} {} +(1, 0) {n, x, y} {r0, x, y} +(1, 1) {r0, x, y} {x, y} +(2, 0) {x, y} {n, x, y} +(2, 1) {n, x, y} {n, x, y} +(3, 0) {n, x, y} {n, r1, x, y} +(3, 1) {n, r1, x, y} {n, x, y} +(4, 0) {x, y} {x, y} +(4, 1) {x, y} {n, x, y} +(4, 2) {n, x, y} {n, x, y} +(5, 0) {n, x, y} {n, x, y} +(6, 0) {} {} [case testCall_Liveness] def f(x: int) -> int: @@ -296,80 +256,35 @@ def f(a: int) -> None: [out] def f(a): a :: int - r0 :: native_int - r1 :: bit - r2 :: native_int - r3, r4, r5 :: bit - r6 :: native_int - r7 :: bit - r8 :: native_int - r9, r10, r11 :: bit + r0, r1 :: bit y, x :: int L0: L1: - r0 = a & 1 - r1 = r0 != 0 - if r1 goto L3 else goto L2 :: bool + r0 = int_lt a, a + if r0 goto L2 else goto L6 :: bool L2: - r2 = a & 1 - r3 = r2 != 0 - if r3 goto L3 else goto L4 :: bool L3: - r4 = CPyTagged_IsLt_(a, a) - if r4 goto L5 else goto L12 :: bool + r1 = int_lt a, a + if r1 goto L4 else goto L5 :: bool L4: - r5 = a < a :: signed - if r5 goto L5 else goto L12 :: bool -L5: -L6: - r6 = a & 1 - r7 = r6 != 0 - if r7 goto L8 else goto L7 :: bool -L7: - r8 = a & 1 - r9 = r8 != 0 - if r9 goto L8 else goto L9 :: bool -L8: - r10 = CPyTagged_IsLt_(a, a) - if r10 goto L10 else goto L11 :: bool -L9: - r11 = a < a :: signed - if r11 goto L10 else goto L11 :: bool -L10: y = a - goto L6 -L11: + goto L3 +L5: x = a goto L1 -L12: +L6: return 1 (0, 0) {a} {a} (1, 0) {a, x, y} {a, x, y} (1, 1) {a, x, y} {a, x, y} -(1, 2) {a, x, y} {a, x, y} (2, 0) {a, x, y} {a, x, y} -(2, 1) {a, x, y} {a, x, y} -(2, 2) {a, x, y} {a, x, y} (3, 0) {a, x, y} {a, x, y} (3, 1) {a, x, y} {a, x, y} (4, 0) {a, x, y} {a, x, y} (4, 1) {a, x, y} {a, x, y} (5, 0) {a, x, y} {a, x, y} +(5, 1) {a, x, y} {a, x, y} (6, 0) {a, x, y} {a, x, y} -(6, 1) {a, x, y} {a, x, y} -(6, 2) {a, x, y} {a, x, y} -(7, 0) {a, x, y} {a, x, y} -(7, 1) {a, x, y} {a, x, y} -(7, 2) {a, x, y} {a, x, y} -(8, 0) {a, x, y} {a, x, y} -(8, 1) {a, x, y} {a, x, y} -(9, 0) {a, x, y} {a, x, y} -(9, 1) {a, x, y} {a, x, y} -(10, 0) {a, x, y} {a, x, y} -(10, 1) {a, x, y} {a, x, y} -(11, 0) {a, x, y} {a, x, y} -(11, 1) {a, x, y} {a, x, y} -(12, 0) {a, x, y} {a, x, y} [case testTrivial_BorrowedArgument] def f(a: int, b: int) -> int: @@ -441,55 +356,33 @@ def f(a: int) -> int: [out] def f(a): a, sum, i :: int - r0 :: native_int - r1 :: bit - r2 :: native_int - r3, r4, r5 :: bit - r6, r7 :: int + r0 :: bit + r1, r2 :: int L0: sum = 0 i = 0 L1: - r0 = i & 1 - r1 = r0 != 0 - if r1 goto L3 else goto L2 :: bool + r0 = int_le i, a + if r0 goto L2 else goto L3 :: bool L2: - r2 = a & 1 - r3 = r2 != 0 - if r3 goto L3 else goto L4 :: bool -L3: - r4 = CPyTagged_IsLt_(a, i) - if r4 goto L6 else goto L5 :: bool -L4: - r5 = i <= a :: signed - if r5 goto L5 else goto L6 :: bool -L5: - r6 = CPyTagged_Add(sum, i) - sum = r6 - r7 = CPyTagged_Add(i, 2) - i = r7 + r1 = CPyTagged_Add(sum, i) + sum = r1 + r2 = CPyTagged_Add(i, 2) + i = r2 goto L1 -L6: +L3: return sum (0, 0) {a} {a} (0, 1) {a} {a} (0, 2) {a} {a} (1, 0) {a} {a} (1, 1) {a} {a} -(1, 2) {a} {a} (2, 0) {a} {a} (2, 1) {a} {a} (2, 2) {a} {a} +(2, 3) {a} {a} +(2, 4) {a} {a} (3, 0) {a} {a} -(3, 1) {a} {a} -(4, 0) {a} {a} -(4, 1) {a} {a} -(5, 0) {a} {a} -(5, 1) {a} {a} -(5, 2) {a} {a} -(5, 3) {a} {a} -(5, 4) {a} {a} -(6, 0) {a} {a} [case testError] def f(x: List[int]) -> None: pass # E: Name "List" is not defined \ diff --git a/mypyc/test-data/exceptions.test b/mypyc/test-data/exceptions.test index ed43b86ebdb4..1ec03dd9a671 100644 --- a/mypyc/test-data/exceptions.test +++ b/mypyc/test-data/exceptions.test @@ -111,56 +111,42 @@ def sum(a: List[int], l: int) -> int: def sum(a, l): a :: list l, sum, i :: int - r0 :: native_int - r1 :: bit - r2 :: native_int - r3, r4, r5 :: bit - r6 :: object - r7, r8, r9, r10 :: int + r0 :: bit + r1 :: object + r2, r3, r4, r5 :: int L0: sum = 0 i = 0 L1: - r0 = i & 1 - r1 = r0 != 0 - if r1 goto L3 else goto L2 :: bool + r0 = int_lt i, l + if r0 goto L2 else goto L7 :: bool L2: - r2 = l & 1 - r3 = r2 != 0 - if r3 goto L3 else goto L4 :: bool + r1 = CPyList_GetItemBorrow(a, i) + if is_error(r1) goto L8 (error at sum:6) else goto L3 L3: - r4 = CPyTagged_IsLt_(i, l) - if r4 goto L5 else goto L10 :: bool + r2 = unbox(int, r1) + if is_error(r2) goto L8 (error at sum:6) else goto L4 L4: - r5 = i < l :: signed - if r5 goto L5 else goto L10 :: bool -L5: - r6 = CPyList_GetItemBorrow(a, i) - if is_error(r6) goto L11 (error at sum:6) else goto L6 -L6: - r7 = unbox(int, r6) - if is_error(r7) goto L11 (error at sum:6) else goto L7 -L7: - r8 = CPyTagged_Add(sum, r7) + r3 = CPyTagged_Add(sum, r2) dec_ref sum :: int - dec_ref r7 :: int - sum = r8 - r9 = CPyTagged_Add(i, 2) + dec_ref r2 :: int + sum = r3 + r4 = CPyTagged_Add(i, 2) dec_ref i :: int - i = r9 + i = r4 goto L1 -L8: +L5: return sum -L9: - r10 = :: int - return r10 -L10: +L6: + r5 = :: int + return r5 +L7: dec_ref i :: int - goto L8 -L11: + goto L5 +L8: dec_ref sum :: int dec_ref i :: int - goto L9 + goto L6 [case testTryExcept] def g() -> None: diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index 981460dae371..164fc213a8a2 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -76,27 +76,13 @@ def f(x: int, y: int) -> int: [out] def f(x, y): x, y :: int - r0 :: native_int - r1 :: bit - r2 :: native_int - r3, r4, r5 :: bit + r0 :: bit L0: - r0 = x & 1 - r1 = r0 != 0 - if r1 goto L2 else goto L1 :: bool + r0 = int_lt x, y + if r0 goto L1 else goto L2 :: bool L1: - r2 = y & 1 - r3 = r2 != 0 - if r3 goto L2 else goto L3 :: bool -L2: - r4 = CPyTagged_IsLt_(x, y) - if r4 goto L4 else goto L5 :: bool -L3: - r5 = x < y :: signed - if r5 goto L4 else goto L5 :: bool -L4: x = 2 -L5: +L2: return x [case testIfElse] @@ -109,30 +95,16 @@ def f(x: int, y: int) -> int: [out] def f(x, y): x, y :: int - r0 :: native_int - r1 :: bit - r2 :: native_int - r3, r4, r5 :: bit + r0 :: bit L0: - r0 = x & 1 - r1 = r0 != 0 - if r1 goto L2 else goto L1 :: bool + r0 = int_lt x, y + if r0 goto L1 else goto L2 :: bool L1: - r2 = y & 1 - r3 = r2 != 0 - if r3 goto L2 else goto L3 :: bool -L2: - r4 = CPyTagged_IsLt_(x, y) - if r4 goto L4 else goto L5 :: bool -L3: - r5 = x < y :: signed - if r5 goto L4 else goto L5 :: bool -L4: x = 2 - goto L6 -L5: + goto L3 +L2: x = 4 -L6: +L3: return x [case testAnd1] @@ -145,48 +117,19 @@ def f(x: int, y: int) -> int: [out] def f(x, y): x, y :: int - r0 :: native_int - r1 :: bit - r2 :: native_int - r3, r4, r5 :: bit - r6 :: native_int - r7 :: bit - r8 :: native_int - r9, r10, r11 :: bit + r0, r1 :: bit L0: - r0 = x & 1 - r1 = r0 != 0 - if r1 goto L2 else goto L1 :: bool + r0 = int_lt x, y + if r0 goto L1 else goto L3 :: bool L1: - r2 = y & 1 - r3 = r2 != 0 - if r3 goto L2 else goto L3 :: bool + r1 = int_gt x, y + if r1 goto L2 else goto L3 :: bool L2: - r4 = CPyTagged_IsLt_(x, y) - if r4 goto L4 else goto L9 :: bool -L3: - r5 = x < y :: signed - if r5 goto L4 else goto L9 :: bool -L4: - r6 = x & 1 - r7 = r6 != 0 - if r7 goto L6 else goto L5 :: bool -L5: - r8 = y & 1 - r9 = r8 != 0 - if r9 goto L6 else goto L7 :: bool -L6: - r10 = CPyTagged_IsLt_(y, x) - if r10 goto L8 else goto L9 :: bool -L7: - r11 = x > y :: signed - if r11 goto L8 else goto L9 :: bool -L8: x = 2 - goto L10 -L9: + goto L4 +L3: x = 4 -L10: +L4: return x [case testAnd2] @@ -221,48 +164,19 @@ def f(x: int, y: int) -> int: [out] def f(x, y): x, y :: int - r0 :: native_int - r1 :: bit - r2 :: native_int - r3, r4, r5 :: bit - r6 :: native_int - r7 :: bit - r8 :: native_int - r9, r10, r11 :: bit + r0, r1 :: bit L0: - r0 = x & 1 - r1 = r0 != 0 - if r1 goto L2 else goto L1 :: bool + r0 = int_lt x, y + if r0 goto L2 else goto L1 :: bool L1: - r2 = y & 1 - r3 = r2 != 0 - if r3 goto L2 else goto L3 :: bool + r1 = int_gt x, y + if r1 goto L2 else goto L3 :: bool L2: - r4 = CPyTagged_IsLt_(x, y) - if r4 goto L8 else goto L4 :: bool -L3: - r5 = x < y :: signed - if r5 goto L8 else goto L4 :: bool -L4: - r6 = x & 1 - r7 = r6 != 0 - if r7 goto L6 else goto L5 :: bool -L5: - r8 = y & 1 - r9 = r8 != 0 - if r9 goto L6 else goto L7 :: bool -L6: - r10 = CPyTagged_IsLt_(y, x) - if r10 goto L8 else goto L9 :: bool -L7: - r11 = x > y :: signed - if r11 goto L8 else goto L9 :: bool -L8: x = 2 - goto L10 -L9: + goto L4 +L3: x = 4 -L10: +L4: return x [case testOr2] @@ -295,27 +209,13 @@ def f(x: int, y: int) -> int: [out] def f(x, y): x, y :: int - r0 :: native_int - r1 :: bit - r2 :: native_int - r3, r4, r5 :: bit + r0 :: bit L0: - r0 = x & 1 - r1 = r0 != 0 - if r1 goto L2 else goto L1 :: bool + r0 = int_lt x, y + if r0 goto L2 else goto L1 :: bool L1: - r2 = y & 1 - r3 = r2 != 0 - if r3 goto L2 else goto L3 :: bool -L2: - r4 = CPyTagged_IsLt_(x, y) - if r4 goto L5 else goto L4 :: bool -L3: - r5 = x < y :: signed - if r5 goto L5 else goto L4 :: bool -L4: x = 2 -L5: +L2: return x [case testNotAnd] @@ -326,45 +226,16 @@ def f(x: int, y: int) -> int: [out] def f(x, y): x, y :: int - r0 :: native_int - r1 :: bit - r2 :: native_int - r3, r4, r5 :: bit - r6 :: native_int - r7 :: bit - r8 :: native_int - r9, r10, r11 :: bit + r0, r1 :: bit L0: - r0 = x & 1 - r1 = r0 != 0 - if r1 goto L2 else goto L1 :: bool + r0 = int_lt x, y + if r0 goto L1 else goto L2 :: bool L1: - r2 = y & 1 - r3 = r2 != 0 - if r3 goto L2 else goto L3 :: bool + r1 = int_gt x, y + if r1 goto L3 else goto L2 :: bool L2: - r4 = CPyTagged_IsLt_(x, y) - if r4 goto L4 else goto L8 :: bool -L3: - r5 = x < y :: signed - if r5 goto L4 else goto L8 :: bool -L4: - r6 = x & 1 - r7 = r6 != 0 - if r7 goto L6 else goto L5 :: bool -L5: - r8 = y & 1 - r9 = r8 != 0 - if r9 goto L6 else goto L7 :: bool -L6: - r10 = CPyTagged_IsLt_(y, x) - if r10 goto L9 else goto L8 :: bool -L7: - r11 = x > y :: signed - if r11 goto L9 else goto L8 :: bool -L8: x = 2 -L9: +L3: return x [case testWhile] @@ -375,31 +246,17 @@ def f(x: int, y: int) -> int: [out] def f(x, y): x, y :: int - r0 :: native_int - r1 :: bit - r2 :: native_int - r3, r4, r5 :: bit - r6 :: int + r0 :: bit + r1 :: int L0: L1: - r0 = x & 1 - r1 = r0 != 0 - if r1 goto L3 else goto L2 :: bool + r0 = int_gt x, y + if r0 goto L2 else goto L3 :: bool L2: - r2 = y & 1 - r3 = r2 != 0 - if r3 goto L3 else goto L4 :: bool -L3: - r4 = CPyTagged_IsLt_(y, x) - if r4 goto L5 else goto L6 :: bool -L4: - r5 = x > y :: signed - if r5 goto L5 else goto L6 :: bool -L5: - r6 = CPyTagged_Subtract(x, y) - x = r6 + r1 = CPyTagged_Subtract(x, y) + x = r1 goto L1 -L6: +L3: return x [case testWhile2] @@ -411,32 +268,18 @@ def f(x: int, y: int) -> int: [out] def f(x, y): x, y :: int - r0 :: native_int - r1 :: bit - r2 :: native_int - r3, r4, r5 :: bit - r6 :: int + r0 :: bit + r1 :: int L0: x = 2 L1: - r0 = x & 1 - r1 = r0 != 0 - if r1 goto L3 else goto L2 :: bool + r0 = int_gt x, y + if r0 goto L2 else goto L3 :: bool L2: - r2 = y & 1 - r3 = r2 != 0 - if r3 goto L3 else goto L4 :: bool -L3: - r4 = CPyTagged_IsLt_(y, x) - if r4 goto L5 else goto L6 :: bool -L4: - r5 = x > y :: signed - if r5 goto L5 else goto L6 :: bool -L5: - r6 = CPyTagged_Subtract(x, y) - x = r6 + r1 = CPyTagged_Subtract(x, y) + x = r1 goto L1 -L6: +L3: return x [case testImplicitNoneReturn] @@ -466,30 +309,16 @@ def f(x: int, y: int) -> None: [out] def f(x, y): x, y :: int - r0 :: native_int - r1 :: bit - r2 :: native_int - r3, r4, r5 :: bit + r0 :: bit L0: - r0 = x & 1 - r1 = r0 != 0 - if r1 goto L2 else goto L1 :: bool + r0 = int_lt x, y + if r0 goto L1 else goto L2 :: bool L1: - r2 = y & 1 - r3 = r2 != 0 - if r3 goto L2 else goto L3 :: bool -L2: - r4 = CPyTagged_IsLt_(x, y) - if r4 goto L4 else goto L5 :: bool -L3: - r5 = x < y :: signed - if r5 goto L4 else goto L5 :: bool -L4: x = 2 - goto L6 -L5: + goto L3 +L2: y = 4 -L6: +L3: return 1 [case testRecursion] @@ -501,29 +330,21 @@ def f(n: int) -> int: [out] def f(n): n :: int - r0 :: native_int - r1, r2, r3 :: bit - r4, r5, r6, r7, r8 :: int + r0 :: bit + r1, r2, r3, r4, r5 :: int L0: - r0 = n & 1 - r1 = r0 != 0 - if r1 goto L1 else goto L2 :: bool + r0 = int_le n, 2 + if r0 goto L1 else goto L2 :: bool L1: - r2 = CPyTagged_IsLt_(2, n) - if r2 goto L4 else goto L3 :: bool + return 2 L2: - r3 = n <= 2 :: signed - if r3 goto L3 else goto L4 :: bool + r1 = CPyTagged_Subtract(n, 2) + r2 = f(r1) + r3 = CPyTagged_Subtract(n, 4) + r4 = f(r3) + r5 = CPyTagged_Add(r2, r4) + return r5 L3: - return 2 -L4: - r4 = CPyTagged_Subtract(n, 2) - r5 = f(r4) - r6 = CPyTagged_Subtract(n, 4) - r7 = f(r6) - r8 = CPyTagged_Add(r5, r7) - return r8 -L5: unreachable [case testReportTypeCheckError] @@ -550,33 +371,25 @@ def f(n: int) -> int: [out] def f(n): n :: int - r0 :: native_int - r1, r2, r3 :: bit + r0 :: bit x :: int - r4 :: bit + r1 :: bit L0: - r0 = n & 1 - r1 = r0 != 0 - if r1 goto L1 else goto L2 :: bool + r0 = int_lt n, 0 + if r0 goto L1 else goto L2 :: bool L1: - r2 = CPyTagged_IsLt_(n, 0) - if r2 goto L3 else goto L4 :: bool + x = 2 + goto L6 L2: - r3 = n < 0 :: signed - if r3 goto L3 else goto L4 :: bool + r1 = int_eq n, 0 + if r1 goto L3 else goto L4 :: bool L3: x = 2 - goto L8 + goto L5 L4: - r4 = int_eq n, 0 - if r4 goto L5 else goto L6 :: bool + x = 4 L5: - x = 2 - goto L7 L6: - x = 4 -L7: -L8: return x [case testUnaryMinus] @@ -1272,27 +1085,19 @@ def f(x: int) -> int: [out] def absolute_value(x): x :: int - r0 :: native_int - r1, r2, r3 :: bit - r4, r5 :: int + r0 :: bit + r1, r2 :: int L0: - r0 = x & 1 - r1 = r0 != 0 - if r1 goto L1 else goto L2 :: bool + r0 = int_gt x, 0 + if r0 goto L1 else goto L2 :: bool L1: - r2 = CPyTagged_IsLt_(0, x) - if r2 goto L3 else goto L4 :: bool + r1 = x + goto L3 L2: - r3 = x > 0 :: signed - if r3 goto L3 else goto L4 :: bool + r2 = CPyTagged_Negate(x) + r1 = r2 L3: - r4 = x - goto L5 -L4: - r5 = CPyTagged_Negate(x) - r4 = r5 -L5: - return r4 + return r1 def call_native_function(x): x, r0 :: int L0: @@ -2078,7 +1883,7 @@ L1: r11 = load_mem r10 :: native_int* keep_alive r1 r12 = r11 << 1 - r13 = r9 < r12 :: signed + r13 = int_lt r9, r12 if r13 goto L2 else goto L8 :: bool L2: r14 = CPyList_GetItemUnsafe(r1, r9) @@ -2148,7 +1953,7 @@ L1: r11 = load_mem r10 :: native_int* keep_alive r1 r12 = r11 << 1 - r13 = r9 < r12 :: signed + r13 = int_lt r9, r12 if r13 goto L2 else goto L8 :: bool L2: r14 = CPyList_GetItemUnsafe(r1, r9) @@ -2215,7 +2020,7 @@ L1: r2 = load_mem r1 :: native_int* keep_alive l r3 = r2 << 1 - r4 = r0 < r3 :: signed + r4 = int_lt r0, r3 if r4 goto L2 else goto L4 :: bool L2: r5 = CPyList_GetItemUnsafe(l, r0) @@ -2241,7 +2046,7 @@ L5: r16 = load_mem r15 :: native_int* keep_alive l r17 = r16 << 1 - r18 = r14 < r17 :: signed + r18 = int_lt r14, r17 if r18 goto L6 else goto L8 :: bool L6: r19 = CPyList_GetItemUnsafe(l, r14) @@ -2504,60 +2309,24 @@ L0: return x def f(x, y, z): x, y, z, r0, r1 :: int - r2 :: native_int - r3 :: bit - r4 :: native_int - r5, r6, r7 :: bit - r8 :: bool - r9 :: bit - r10 :: bool - r11 :: int - r12 :: native_int - r13 :: bit - r14 :: native_int - r15, r16, r17 :: bit - r18 :: bool - r19 :: bit + r2 :: bit + r3 :: bool + r4 :: int + r5 :: bit L0: r0 = g(x) r1 = g(y) - r2 = r0 & 1 - r3 = r2 == 0 - r4 = r1 & 1 - r5 = r4 == 0 - r6 = r3 & r5 - if r6 goto L1 else goto L2 :: bool + r2 = int_lt r0, r1 + if r2 goto L2 else goto L1 :: bool L1: - r7 = r0 < r1 :: signed - r8 = r7 + r3 = r2 goto L3 L2: - r9 = CPyTagged_IsLt_(r0, r1) - r8 = r9 + r4 = g(z) + r5 = int_gt r1, r4 + r3 = r5 L3: - if r8 goto L5 else goto L4 :: bool -L4: - r10 = r8 - goto L9 -L5: - r11 = g(z) - r12 = r1 & 1 - r13 = r12 == 0 - r14 = r11 & 1 - r15 = r14 == 0 - r16 = r13 & r15 - if r16 goto L6 else goto L7 :: bool -L6: - r17 = r1 > r11 :: signed - r18 = r17 - goto L8 -L7: - r19 = CPyTagged_IsLt_(r11, r1) - r18 = r19 -L8: - r10 = r18 -L9: - return r10 + return r3 [case testEq] class A: @@ -3577,7 +3346,7 @@ L0: r0 = 8 i = r0 L1: - r1 = r0 < 24 :: signed + r1 = int_lt r0, 24 if r1 goto L2 else goto L4 :: bool L2: r2 = CPyTagged_Add(sum, i) diff --git a/mypyc/test-data/irbuild-bool.test b/mypyc/test-data/irbuild-bool.test index f0b0b480bc0d..795a3360fcd2 100644 --- a/mypyc/test-data/irbuild-bool.test +++ b/mypyc/test-data/irbuild-bool.test @@ -272,59 +272,23 @@ def lt1(x, y): x :: bool y :: int r0 :: bool - r1 :: short_int - r2 :: native_int - r3 :: bit - r4 :: native_int - r5, r6, r7 :: bit - r8 :: bool - r9 :: bit + r1 :: int + r2 :: bit L0: r0 = x << 1 - r1 = extend r0: builtins.bool to short_int - r2 = r1 & 1 - r3 = r2 == 0 - r4 = y & 1 - r5 = r4 == 0 - r6 = r3 & r5 - if r6 goto L1 else goto L2 :: bool -L1: - r7 = r1 < y :: signed - r8 = r7 - goto L3 -L2: - r9 = CPyTagged_IsLt_(r1, y) - r8 = r9 -L3: - return r8 + r1 = extend r0: builtins.bool to builtins.int + r2 = int_lt r1, y + return r2 def lt2(x, y): x :: int y, r0 :: bool - r1 :: short_int - r2 :: native_int - r3 :: bit - r4 :: native_int - r5, r6, r7 :: bit - r8 :: bool - r9 :: bit + r1 :: int + r2 :: bit L0: r0 = y << 1 - r1 = extend r0: builtins.bool to short_int - r2 = x & 1 - r3 = r2 == 0 - r4 = r1 & 1 - r5 = r4 == 0 - r6 = r3 & r5 - if r6 goto L1 else goto L2 :: bool -L1: - r7 = x < r1 :: signed - r8 = r7 - goto L3 -L2: - r9 = CPyTagged_IsLt_(x, r1) - r8 = r9 -L3: - return r8 + r1 = extend r0: builtins.bool to builtins.int + r2 = int_lt x, r1 + return r2 def gt1(x, y): x :: bool y, r0 :: i64 diff --git a/mypyc/test-data/irbuild-dunders.test b/mypyc/test-data/irbuild-dunders.test index b50b6eeae162..1796a7e2160e 100644 --- a/mypyc/test-data/irbuild-dunders.test +++ b/mypyc/test-data/irbuild-dunders.test @@ -15,24 +15,16 @@ L0: def f(c): c :: __main__.C r0 :: int - r1 :: native_int - r2, r3, r4 :: bit - r5 :: bool + r1 :: bit + r2 :: bool L0: r0 = c.__len__() - r1 = r0 & 1 - r2 = r1 != 0 - if r2 goto L1 else goto L2 :: bool + r1 = int_ge r0, 0 + if r1 goto L2 else goto L1 :: bool L1: - r3 = CPyTagged_IsLt_(r0, 0) - if r3 goto L3 else goto L4 :: bool -L2: - r4 = r0 >= 0 :: signed - if r4 goto L4 else goto L3 :: bool -L3: - r5 = raise ValueError('__len__() should return >= 0') + r2 = raise ValueError('__len__() should return >= 0') unreachable -L4: +L2: return r0 [case testDundersSetItem] diff --git a/mypyc/test-data/irbuild-int.test b/mypyc/test-data/irbuild-int.test index 1489f2f470dd..b1a712103e70 100644 --- a/mypyc/test-data/irbuild-int.test +++ b/mypyc/test-data/irbuild-int.test @@ -25,9 +25,7 @@ def f(x: int) -> int: [out] def f(x): x :: int - r0, r1, r2, r3 :: bit - r4 :: native_int - r5, r6, r7 :: bit + r0, r1, r2, r3, r4 :: bit L0: r0 = int_eq x, 6 if r0 goto L1 else goto L2 :: bool @@ -49,22 +47,15 @@ L6: L7: return 8 L8: - r4 = x & 1 - r5 = r4 != 0 - if r5 goto L9 else goto L10 :: bool + r4 = int_lt x, 8 + if r4 goto L9 else goto L10 :: bool L9: - r6 = CPyTagged_IsLt_(x, 8) - if r6 goto L11 else goto L12 :: bool + return 10 L10: - r7 = x < 8 :: signed - if r7 goto L11 else goto L12 :: bool L11: - return 10 L12: L13: L14: -L15: -L16: return 12 [case testIntMin] @@ -73,36 +64,18 @@ def f(x: int, y: int) -> int: [out] def f(x, y): x, y :: int - r0 :: native_int - r1 :: bit - r2 :: native_int - r3, r4, r5 :: bit - r6 :: bool - r7 :: bit - r8 :: int -L0: - r0 = y & 1 - r1 = r0 == 0 - r2 = x & 1 - r3 = r2 == 0 - r4 = r1 & r3 - if r4 goto L1 else goto L2 :: bool + r0 :: bit + r1 :: int +L0: + r0 = int_lt y, x + if r0 goto L1 else goto L2 :: bool L1: - r5 = y < x :: signed - r6 = r5 + r1 = y goto L3 L2: - r7 = CPyTagged_IsLt_(y, x) - r6 = r7 + r1 = x L3: - if r6 goto L4 else goto L5 :: bool -L4: - r8 = y - goto L6 -L5: - r8 = x -L6: - return r8 + return r1 [case testIntFloorDivideByPowerOfTwo] def divby1(x: int) -> int: diff --git a/mypyc/test-data/irbuild-lists.test b/mypyc/test-data/irbuild-lists.test index 80c4fe5fcd5e..ced4646922a3 100644 --- a/mypyc/test-data/irbuild-lists.test +++ b/mypyc/test-data/irbuild-lists.test @@ -230,7 +230,7 @@ L0: r3 = 0 i = r3 L1: - r4 = r3 < r2 :: signed + r4 = int_lt r3, r2 if r4 goto L2 else goto L4 :: bool L2: r5 = CPyList_GetItem(l, i) @@ -357,7 +357,7 @@ L1: r5 = load_mem r4 :: native_int* keep_alive source r6 = r5 << 1 - r7 = r3 < r6 :: signed + r7 = int_lt r3, r6 if r7 goto L2 else goto L4 :: bool L2: r8 = CPyList_GetItemUnsafe(source, r3) @@ -382,7 +382,7 @@ L5: r19 = load_mem r18 :: native_int* keep_alive source r20 = r19 << 1 - r21 = r17 < r20 :: signed + r21 = int_lt r17, r20 if r21 goto L6 else goto L8 :: bool L6: r22 = CPyList_GetItemUnsafe(source, r17) @@ -398,6 +398,7 @@ L7: L8: b = r16 return 1 + [case testGeneratorNext] from typing import List, Optional @@ -425,7 +426,7 @@ L1: r2 = load_mem r1 :: native_int* keep_alive x r3 = r2 << 1 - r4 = r0 < r3 :: signed + r4 = int_lt r0, r3 if r4 goto L2 else goto L4 :: bool L2: r5 = CPyList_GetItemUnsafe(x, r0) @@ -504,7 +505,7 @@ L1: r2 = load_mem r1 :: native_int* keep_alive a r3 = r2 << 1 - r4 = r0 < r3 :: signed + r4 = int_lt r0, r3 if r4 goto L2 else goto L4 :: bool L2: r5 = CPyList_GetItemUnsafe(a, r0) @@ -533,7 +534,7 @@ L1: r2 = load_mem r1 :: native_int* keep_alive a r3 = r2 << 1 - r4 = r0 < r3 :: signed + r4 = int_lt r0, r3 if r4 goto L2 else goto L4 :: bool L2: r5 = CPyList_GetItemUnsafe(a, r0) diff --git a/mypyc/test-data/irbuild-set.test b/mypyc/test-data/irbuild-set.test index a56ebe3438fa..51feab332593 100644 --- a/mypyc/test-data/irbuild-set.test +++ b/mypyc/test-data/irbuild-set.test @@ -115,7 +115,7 @@ L1: r11 = load_mem r10 :: native_int* keep_alive tmp_list r12 = r11 << 1 - r13 = r9 < r12 :: signed + r13 = int_lt r9, r12 if r13 goto L2 else goto L4 :: bool L2: r14 = CPyList_GetItemUnsafe(tmp_list, r9) @@ -234,7 +234,7 @@ L0: r1 = 2 x = r1 L1: - r2 = r1 < 12 :: signed + r2 = int_lt r1, 12 if r2 goto L2 else goto L4 :: bool L2: r3 = f(x) @@ -265,7 +265,7 @@ L0: r1 = 2 x = r1 L1: - r2 = r1 < 12 :: signed + r2 = int_lt r1, 12 if r2 goto L2 else goto L4 :: bool L2: r3 = f(x) @@ -323,27 +323,22 @@ def test(): r19 :: bit r20 :: object r21, z :: int - r22 :: native_int - r23 :: bit - r24 :: native_int - r25, r26, r27 :: bit - r28 :: bool - r29 :: bit - r30 :: int - r31 :: object - r32 :: i32 - r33 :: bit - r34 :: short_int - r35, r36, r37 :: object - r38, y, r39 :: int - r40 :: object - r41 :: i32 - r42, r43 :: bit - r44, r45, r46 :: object - r47, x, r48 :: int - r49 :: object - r50 :: i32 - r51, r52 :: bit + 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 a :: set L0: r0 = PyList_New(5) @@ -374,73 +369,60 @@ L1: r17 = load_mem r16 :: native_int* keep_alive tmp_list r18 = r17 << 1 - r19 = r15 < r18 :: signed - if r19 goto L2 else goto L9 :: bool + r19 = int_lt r15, r18 + if r19 goto L2 else goto L6 :: bool L2: r20 = CPyList_GetItemUnsafe(tmp_list, r15) r21 = unbox(int, r20) z = r21 - r22 = z & 1 - r23 = r22 == 0 - r24 = 8 & 1 - r25 = r24 == 0 - r26 = r23 & r25 - if r26 goto L3 else goto L4 :: bool + r22 = int_lt z, 8 + if r22 goto L4 else goto L3 :: bool L3: - r27 = z < 8 :: signed - r28 = r27 goto L5 L4: - r29 = CPyTagged_IsLt_(z, 8) - r28 = r29 + r23 = f1(z) + r24 = box(int, r23) + r25 = PyList_Append(r14, r24) + r26 = r25 >= 0 :: signed L5: - if r28 goto L7 else goto L6 :: bool + r27 = r15 + 2 + r15 = r27 + goto L1 L6: - goto L8 + r28 = PyObject_GetIter(r14) + r29 = PyObject_GetIter(r28) L7: - r30 = f1(z) - r31 = box(int, r30) - r32 = PyList_Append(r14, r31) - r33 = r32 >= 0 :: signed + r30 = PyIter_Next(r29) + if is_error(r30) goto L10 else goto L8 L8: - r34 = r15 + 2 - r15 = r34 - goto L1 + r31 = unbox(int, r30) + y = r31 + r32 = f2(y) + r33 = box(int, r32) + r34 = PyList_Append(r13, r33) + r35 = r34 >= 0 :: signed L9: - r35 = PyObject_GetIter(r14) - r36 = PyObject_GetIter(r35) + goto L7 L10: - r37 = PyIter_Next(r36) - if is_error(r37) goto L13 else goto L11 + r36 = CPy_NoErrOccured() L11: - r38 = unbox(int, r37) - y = r38 - r39 = f2(y) - r40 = box(int, r39) - r41 = PyList_Append(r13, r40) - r42 = r41 >= 0 :: signed + r37 = PyObject_GetIter(r13) + r38 = PyObject_GetIter(r37) L12: - goto L10 + r39 = PyIter_Next(r38) + if is_error(r39) goto L15 else goto L13 L13: - r43 = CPy_NoErrOccured() + r40 = unbox(int, r39) + x = r40 + r41 = f3(x) + r42 = box(int, r41) + r43 = PySet_Add(r12, r42) + r44 = r43 >= 0 :: signed L14: - r44 = PyObject_GetIter(r13) - r45 = PyObject_GetIter(r44) + goto L12 L15: - r46 = PyIter_Next(r45) - if is_error(r46) goto L18 else goto L16 + r45 = CPy_NoErrOccured() L16: - r47 = unbox(int, r46) - x = r47 - r48 = f3(x) - r49 = box(int, r48) - r50 = PySet_Add(r12, r49) - r51 = r50 >= 0 :: signed -L17: - goto L15 -L18: - r52 = CPy_NoErrOccured() -L19: a = r12 return 1 diff --git a/mypyc/test-data/irbuild-singledispatch.test b/mypyc/test-data/irbuild-singledispatch.test index 10970a385966..e1053397546f 100644 --- a/mypyc/test-data/irbuild-singledispatch.test +++ b/mypyc/test-data/irbuild-singledispatch.test @@ -81,7 +81,7 @@ L3: if r17 goto L4 else goto L7 :: bool L4: r18 = unbox(int, r6) - r19 = r18 == 0 + r19 = int_eq r18, 0 if r19 goto L5 else goto L6 :: bool L5: r20 = unbox(int, arg) diff --git a/mypyc/test-data/irbuild-statements.test b/mypyc/test-data/irbuild-statements.test index b7c67730a05f..ed97c4cd4138 100644 --- a/mypyc/test-data/irbuild-statements.test +++ b/mypyc/test-data/irbuild-statements.test @@ -16,7 +16,7 @@ L0: r0 = 0 i = r0 L1: - r1 = r0 < 10 :: signed + r1 = int_lt r0, 10 if r1 goto L2 else goto L4 :: bool L2: r2 = CPyTagged_Add(x, i) @@ -36,39 +36,21 @@ def f(a: int) -> None: [out] def f(a): a, r0, i :: int - r1 :: native_int - r2 :: bit - r3 :: native_int - r4, r5, r6 :: bit - r7 :: bool - r8 :: bit - r9 :: int + r1 :: bit + r2 :: int L0: r0 = 0 i = r0 L1: - r1 = r0 & 1 - r2 = r1 == 0 - r3 = a & 1 - r4 = r3 == 0 - r5 = r2 & r4 - if r5 goto L2 else goto L3 :: bool + r1 = int_lt r0, a + if r1 goto L2 else goto L4 :: bool L2: - r6 = r0 < a :: signed - r7 = r6 - goto L4 L3: - r8 = CPyTagged_IsLt_(r0, a) - r7 = r8 -L4: - if r7 goto L5 else goto L7 :: bool -L5: -L6: - r9 = CPyTagged_Add(r0, 2) - r0 = r9 - i = r9 + r2 = CPyTagged_Add(r0, 2) + r0 = r2 + i = r2 goto L1 -L7: +L4: return 1 [case testForInNegativeRange] @@ -85,7 +67,7 @@ L0: r0 = 20 i = r0 L1: - r1 = r0 > 0 :: signed + r1 = int_gt r0, 0 if r1 goto L2 else goto L4 :: bool L2: L3: @@ -104,22 +86,14 @@ def f() -> None: [out] def f(): n :: int - r0 :: native_int - r1, r2, r3 :: bit + r0 :: bit L0: n = 0 L1: - r0 = n & 1 - r1 = r0 != 0 - if r1 goto L2 else goto L3 :: bool + r0 = int_lt n, 10 + if r0 goto L2 else goto L3 :: bool L2: - r2 = CPyTagged_IsLt_(n, 10) - if r2 goto L4 else goto L5 :: bool L3: - r3 = n < 10 :: signed - if r3 goto L4 else goto L5 :: bool -L4: -L5: return 1 [case testBreakFor] @@ -136,7 +110,7 @@ L0: r0 = 0 n = r0 L1: - r1 = r0 < 10 :: signed + r1 = int_lt r0, 10 if r1 goto L2 else goto L4 :: bool L2: goto L4 @@ -158,36 +132,19 @@ def f() -> None: [out] def f(): n :: int - r0 :: native_int - r1, r2, r3 :: bit - r4 :: native_int - r5, r6, r7 :: bit + r0, r1 :: bit L0: n = 0 L1: - r0 = n & 1 - r1 = r0 != 0 - if r1 goto L2 else goto L3 :: bool + r0 = int_lt n, 10 + if r0 goto L2 else goto L6 :: bool L2: - r2 = CPyTagged_IsLt_(n, 10) - if r2 goto L4 else goto L10 :: bool L3: - r3 = n < 10 :: signed - if r3 goto L4 else goto L10 :: bool + r1 = int_lt n, 8 + if r1 goto L4 else goto L5 :: bool L4: L5: - r4 = n & 1 - r5 = r4 != 0 - if r5 goto L6 else goto L7 :: bool L6: - r6 = CPyTagged_IsLt_(n, 8) - if r6 goto L8 else goto L9 :: bool -L7: - r7 = n < 8 :: signed - if r7 goto L8 else goto L9 :: bool -L8: -L9: -L10: return 1 [case testContinue] @@ -198,23 +155,15 @@ def f() -> None: [out] def f(): n :: int - r0 :: native_int - r1, r2, r3 :: bit + r0 :: bit L0: n = 0 L1: - r0 = n & 1 - r1 = r0 != 0 - if r1 goto L2 else goto L3 :: bool + r0 = int_lt n, 10 + if r0 goto L2 else goto L3 :: bool L2: - r2 = CPyTagged_IsLt_(n, 10) - if r2 goto L4 else goto L5 :: bool -L3: - r3 = n < 10 :: signed - if r3 goto L4 else goto L5 :: bool -L4: goto L1 -L5: +L3: return 1 [case testContinueFor] @@ -231,7 +180,7 @@ L0: r0 = 0 n = r0 L1: - r1 = r0 < 10 :: signed + r1 = int_lt r0, 10 if r1 goto L2 else goto L4 :: bool L2: L3: @@ -252,38 +201,21 @@ def f() -> None: [out] def f(): n :: int - r0 :: native_int - r1, r2, r3 :: bit - r4 :: native_int - r5, r6, r7 :: bit + r0, r1 :: bit L0: n = 0 L1: - r0 = n & 1 - r1 = r0 != 0 - if r1 goto L2 else goto L3 :: bool + r0 = int_lt n, 10 + if r0 goto L2 else goto L6 :: bool L2: - r2 = CPyTagged_IsLt_(n, 10) - if r2 goto L4 else goto L10 :: bool L3: - r3 = n < 10 :: signed - if r3 goto L4 else goto L10 :: bool + r1 = int_lt n, 8 + if r1 goto L4 else goto L5 :: bool L4: + goto L3 L5: - r4 = n & 1 - r5 = r4 != 0 - if r5 goto L6 else goto L7 :: bool -L6: - r6 = CPyTagged_IsLt_(n, 8) - if r6 goto L8 else goto L9 :: bool -L7: - r7 = n < 8 :: signed - if r7 goto L8 else goto L9 :: bool -L8: - goto L5 -L9: goto L1 -L10: +L6: return 1 [case testForList] @@ -314,7 +246,7 @@ L1: r2 = load_mem r1 :: native_int* keep_alive ls r3 = r2 << 1 - r4 = r0 < r3 :: signed + r4 = int_lt r0, r3 if r4 goto L2 else goto L4 :: bool L2: r5 = CPyList_GetItemUnsafe(ls, r0) @@ -963,7 +895,7 @@ L1: r3 = load_mem r2 :: native_int* keep_alive a r4 = r3 << 1 - r5 = r1 < r4 :: signed + r5 = int_lt r1, r4 if r5 goto L2 else goto L4 :: bool L2: r6 = CPyList_GetItemUnsafe(a, r1) @@ -1045,7 +977,7 @@ L1: r3 = load_mem r2 :: native_int* keep_alive a r4 = r3 << 1 - r5 = r0 < r4 :: signed + r5 = int_lt r0, r4 if r5 goto L2 else goto L7 :: bool L2: r6 = PyIter_Next(r1) @@ -1100,10 +1032,10 @@ L2: r5 = load_mem r4 :: native_int* keep_alive b r6 = r5 << 1 - r7 = r1 < r6 :: signed + r7 = int_lt r1, r6 if r7 goto L3 else goto L6 :: bool L3: - r8 = r2 < 10 :: signed + r8 = int_lt r2, 10 if r8 goto L4 else goto L6 :: bool L4: r9 = unbox(bool, r3) diff --git a/mypyc/test-data/irbuild-tuple.test b/mypyc/test-data/irbuild-tuple.test index ab0e2fa09a9d..342bb19b5360 100644 --- a/mypyc/test-data/irbuild-tuple.test +++ b/mypyc/test-data/irbuild-tuple.test @@ -147,7 +147,7 @@ L1: r2 = load_mem r1 :: native_int* keep_alive xs r3 = r2 << 1 - r4 = r0 < r3 :: signed + r4 = int_lt r0, r3 if r4 goto L2 else goto L4 :: bool L2: r5 = CPySequenceTuple_GetItem(xs, r0) @@ -279,7 +279,7 @@ L1: r13 = load_mem r12 :: native_int* keep_alive source r14 = r13 << 1 - r15 = r11 < r14 :: signed + r15 = int_lt r11, r14 if r15 goto L2 else goto L4 :: bool L2: r16 = CPyList_GetItemUnsafe(source, r11) @@ -335,7 +335,7 @@ L1: r5 = CPyStr_Size_size_t(source) r6 = r5 >= 0 :: signed r7 = r5 << 1 - r8 = r4 < r7 :: signed + r8 = int_lt r4, r7 if r8 goto L2 else goto L4 :: bool L2: r9 = CPyStr_GetItem(source, r4) @@ -391,7 +391,7 @@ L1: r5 = load_mem r4 :: native_int* keep_alive source r6 = r5 << 1 - r7 = r3 < r6 :: signed + r7 = int_lt r3, r6 if r7 goto L2 else goto L4 :: bool L2: r8 = CPySequenceTuple_GetItem(source, r3) diff --git a/mypyc/test-data/lowering-int.test b/mypyc/test-data/lowering-int.test index 8c813563d0e6..e7df944c4458 100644 --- a/mypyc/test-data/lowering-int.test +++ b/mypyc/test-data/lowering-int.test @@ -13,13 +13,13 @@ def f(x, y): r1, r2, r3 :: bit L0: r0 = x & 1 - r1 = r0 == 0 + r1 = r0 != 0 if r1 goto L1 else goto L2 :: bool L1: - r2 = x == y + r2 = CPyTagged_IsEq_(x, y) if r2 goto L3 else goto L4 :: bool L2: - r3 = CPyTagged_IsEq_(x, y) + r3 = x == y if r3 goto L3 else goto L4 :: bool L3: return 2 @@ -39,14 +39,14 @@ def f(x, y): r1, r2, r3, r4 :: bit L0: r0 = x & 1 - r1 = r0 == 0 + r1 = r0 != 0 if r1 goto L1 else goto L2 :: bool L1: - r2 = x != y - if r2 goto L3 else goto L4 :: bool + r2 = CPyTagged_IsEq_(x, y) + r3 = r2 ^ 1 + if r3 goto L3 else goto L4 :: bool L2: - r3 = CPyTagged_IsEq_(x, y) - r4 = r3 ^ 1 + r4 = x != y if r4 goto L3 else goto L4 :: bool L3: return 2 @@ -113,14 +113,265 @@ def f(x, y): r4 :: bit L0: r0 = x & 1 - r1 = r0 == 0 + r1 = r0 != 0 if r1 goto L1 else goto L2 :: bool L1: - r2 = x == y + r2 = CPyTagged_IsEq_(x, y) r3 = r2 goto L3 L2: - r4 = CPyTagged_IsEq_(x, y) + r4 = x == y r3 = r4 L3: return r3 + +[case testLowerIntLt] +def f(x: int, y: int) -> int: + if x < y: + return 1 + else: + return 2 +[out] +def f(x, y): + x, y :: int + r0 :: native_int + r1 :: bit + r2 :: native_int + r3, r4, r5 :: bit +L0: + r0 = x & 1 + r1 = r0 != 0 + if r1 goto L2 else goto L1 :: bool +L1: + r2 = y & 1 + r3 = r2 != 0 + if r3 goto L2 else goto L3 :: bool +L2: + r4 = CPyTagged_IsLt_(x, y) + if r4 goto L4 else goto L5 :: bool +L3: + r5 = x < y :: signed + if r5 goto L4 else goto L5 :: bool +L4: + return 2 +L5: + return 4 + +[case testLowerIntLe] +def f(x: int, y: int) -> int: + if x <= y: + return 1 + else: + return 2 +[out] +def f(x, y): + x, y :: int + r0 :: native_int + r1 :: bit + r2 :: native_int + r3, r4, r5, r6 :: bit +L0: + r0 = x & 1 + r1 = r0 != 0 + if r1 goto L2 else goto L1 :: bool +L1: + r2 = y & 1 + r3 = r2 != 0 + if r3 goto L2 else goto L3 :: bool +L2: + r4 = CPyTagged_IsLt_(y, x) + r5 = r4 ^ 1 + if r5 goto L4 else goto L5 :: bool +L3: + r6 = x <= y :: signed + if r6 goto L4 else goto L5 :: bool +L4: + return 2 +L5: + return 4 + +[case testLowerIntGt] +def f(x: int, y: int) -> int: + if x > y: + return 1 + else: + return 2 +[out] +def f(x, y): + x, y :: int + r0 :: native_int + r1 :: bit + r2 :: native_int + r3, r4, r5 :: bit +L0: + r0 = x & 1 + r1 = r0 != 0 + if r1 goto L2 else goto L1 :: bool +L1: + r2 = y & 1 + r3 = r2 != 0 + if r3 goto L2 else goto L3 :: bool +L2: + r4 = CPyTagged_IsLt_(y, x) + if r4 goto L4 else goto L5 :: bool +L3: + r5 = x > y :: signed + if r5 goto L4 else goto L5 :: bool +L4: + return 2 +L5: + return 4 + +[case testLowerIntGe] +def f(x: int, y: int) -> int: + if x >= y: + return 1 + else: + return 2 +[out] +def f(x, y): + x, y :: int + r0 :: native_int + r1 :: bit + r2 :: native_int + r3, r4, r5, r6 :: bit +L0: + r0 = x & 1 + r1 = r0 != 0 + if r1 goto L2 else goto L1 :: bool +L1: + r2 = y & 1 + r3 = r2 != 0 + if r3 goto L2 else goto L3 :: bool +L2: + r4 = CPyTagged_IsLt_(x, y) + r5 = r4 ^ 1 + if r5 goto L4 else goto L5 :: bool +L3: + r6 = x >= y :: signed + if r6 goto L4 else goto L5 :: bool +L4: + return 2 +L5: + return 4 + +[case testLowerIntLtShort] +def both() -> int: + if 3 < 5: + return 1 + else: + return 2 + +def rhs_only(x: int) -> int: + if x < 5: + return 1 + else: + return 2 + +def lhs_only(x: int) -> int: + if 5 < x: + return 1 + else: + return 2 +[out] +def both(): + r0 :: bit +L0: + r0 = 6 < 10 :: signed + if r0 goto L1 else goto L2 :: bool +L1: + return 2 +L2: + return 4 +def rhs_only(x): + x :: int + r0 :: native_int + r1 :: bit + r2 :: native_int + r3, r4, r5 :: bit +L0: + r0 = x & 1 + r1 = r0 != 0 + if r1 goto L2 else goto L1 :: bool +L1: + r2 = 10 & 1 + r3 = r2 != 0 + if r3 goto L2 else goto L3 :: bool +L2: + r4 = CPyTagged_IsLt_(x, 10) + if r4 goto L4 else goto L5 :: bool +L3: + r5 = x < 10 :: signed + if r5 goto L4 else goto L5 :: bool +L4: + return 2 +L5: + return 4 +def lhs_only(x): + x :: int + r0 :: native_int + r1 :: bit + r2 :: native_int + r3, r4, r5 :: bit +L0: + r0 = 10 & 1 + r1 = r0 != 0 + if r1 goto L2 else goto L1 :: bool +L1: + r2 = x & 1 + r3 = r2 != 0 + if r3 goto L2 else goto L3 :: bool +L2: + r4 = CPyTagged_IsLt_(10, x) + if r4 goto L4 else goto L5 :: bool +L3: + r5 = 10 < x :: signed + if r5 goto L4 else goto L5 :: bool +L4: + return 2 +L5: + return 4 + +[case testLowerIntForLoop] +from __future__ import annotations + +def f(l: list[int]) -> None: + for x in l: + pass +[out] +def f(l): + l :: list + r0 :: short_int + r1 :: ptr + r2 :: native_int + r3 :: short_int + r4 :: bit + r5 :: object + r6, x :: int + r7 :: short_int + r8 :: None +L0: + r0 = 0 +L1: + 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 L5 :: bool +L2: + r5 = CPyList_GetItemUnsafe(l, r0) + r6 = unbox(int, r5) + dec_ref r5 + if is_error(r6) goto L6 (error at f:4) else goto L3 +L3: + x = r6 + dec_ref x :: int +L4: + r7 = r0 + 2 + r0 = r7 + goto L1 +L5: + return 1 +L6: + r8 = :: None + return r8 diff --git a/mypyc/test-data/refcount.test b/mypyc/test-data/refcount.test index df980af8a7c7..3021381abded 100644 --- a/mypyc/test-data/refcount.test +++ b/mypyc/test-data/refcount.test @@ -452,41 +452,27 @@ def f(a: int) -> int: [out] def f(a): a, sum, i :: int - r0 :: native_int - r1 :: bit - r2 :: native_int - r3, r4, r5 :: bit - r6, r7 :: int + r0 :: bit + r1, r2 :: int L0: sum = 0 i = 0 L1: - r0 = i & 1 - r1 = r0 != 0 - if r1 goto L3 else goto L2 :: bool + r0 = int_le i, a + if r0 goto L2 else goto L4 :: bool L2: - r2 = a & 1 - r3 = r2 != 0 - if r3 goto L3 else goto L4 :: bool -L3: - r4 = CPyTagged_IsLt_(a, i) - if r4 goto L7 else goto L5 :: bool -L4: - r5 = i <= a :: signed - if r5 goto L5 else goto L7 :: bool -L5: - r6 = CPyTagged_Add(sum, i) + r1 = CPyTagged_Add(sum, i) dec_ref sum :: int - sum = r6 - r7 = CPyTagged_Add(i, 2) + sum = r1 + r2 = CPyTagged_Add(i, 2) dec_ref i :: int - i = r7 + i = r2 goto L1 -L6: +L3: return sum -L7: +L4: dec_ref i :: int - goto L6 + goto L3 [case testCall] def f(a: int) -> int: @@ -1357,30 +1343,12 @@ class C: def add(c): c :: __main__.C r0, r1 :: int - r2 :: native_int - r3 :: bit - r4 :: native_int - r5, r6, r7 :: bit - r8 :: bool - r9 :: bit + r2 :: bit L0: r0 = borrow c.x r1 = borrow c.y - r2 = r0 & 1 - r3 = r2 == 0 - r4 = r1 & 1 - r5 = r4 == 0 - r6 = r3 & r5 - if r6 goto L1 else goto L2 :: bool -L1: - r7 = r0 < r1 :: signed - r8 = r7 - goto L3 -L2: - r9 = CPyTagged_IsLt_(r0, r1) - r8 = r9 -L3: - return r8 + r2 = int_lt r0, r1 + return r2 [case testBorrowIntCompareFinal] from typing_extensions import Final