Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f73834e

Browse files
authored
[mypyc] Low-level integer operations: integer equals (#9116)
Relates to mypyc/mypyc#741, mypyc/mypyc#743.
1 parent 82634ed commit f73834e

7 files changed

Lines changed: 247 additions & 88 deletions

File tree

mypyc/irbuild/builder.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,9 @@ def call_c(self, desc: CFunctionDescription, args: List[Value], line: int) -> Va
235235
def binary_int_op(self, type: RType, lhs: Value, rhs: Value, op: int, line: int) -> Value:
236236
return self.builder.binary_int_op(type, lhs, rhs, op, line)
237237

238+
def compare_tagged(self, lhs: Value, rhs: Value, op: str, line: int) -> Value:
239+
return self.builder.compare_tagged(lhs, rhs, op, line)
240+
238241
@property
239242
def environment(self) -> Environment:
240243
return self.builder.environment

mypyc/irbuild/expression.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from mypyc.ir.ops import (
1919
Value, TupleGet, TupleSet, PrimitiveOp, BasicBlock, OpDescription, Assign
2020
)
21-
from mypyc.ir.rtypes import RTuple, object_rprimitive, is_none_rprimitive
21+
from mypyc.ir.rtypes import RTuple, object_rprimitive, is_none_rprimitive, is_int_rprimitive
2222
from mypyc.ir.func_ir import FUNC_CLASSMETHOD, FUNC_STATICMETHOD
2323
from mypyc.primitives.registry import name_ref_ops, CFunctionDescription
2424
from mypyc.primitives.generic_ops import iter_op
@@ -27,6 +27,7 @@
2727
from mypyc.primitives.tuple_ops import list_tuple_op
2828
from mypyc.primitives.dict_ops import dict_new_op, dict_set_item_op
2929
from mypyc.primitives.set_ops import new_set_op, set_add_op, set_update_op
30+
from mypyc.primitives.int_ops import int_logical_op_mapping
3031
from mypyc.irbuild.specialize import specializers
3132
from mypyc.irbuild.builder import IRBuilder
3233
from mypyc.irbuild.for_helpers import translate_list_comprehension, comprehension_helper
@@ -382,6 +383,9 @@ def transform_basic_comparison(builder: IRBuilder,
382383
left: Value,
383384
right: Value,
384385
line: int) -> Value:
386+
if (is_int_rprimitive(left.type) and is_int_rprimitive(right.type)
387+
and op in int_logical_op_mapping.keys()):
388+
return builder.compare_tagged(left, right, op, line)
385389
negate = False
386390
if op == 'is not':
387391
op, negate = 'is', True

mypyc/irbuild/ll_builder.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
from mypyc.primitives.misc_ops import (
5353
none_op, none_object_op, false_op, fast_isinstance_op, bool_op, type_is_op
5454
)
55+
from mypyc.primitives.int_ops import int_logical_op_mapping
5556
from mypyc.rt_subtype import is_runtime_subtype
5657
from mypyc.subtype import is_subtype
5758
from mypyc.sametype import is_same_type
@@ -555,6 +556,34 @@ def binary_op(self,
555556
assert target, 'Unsupported binary operation: %s' % expr_op
556557
return target
557558

559+
def check_tagged_short_int(self, val: Value, line: int) -> Value:
560+
"""Check if a tagged integer is a short integer"""
561+
int_tag = self.add(LoadInt(1, line, rtype=c_pyssize_t_rprimitive))
562+
bitwise_and = self.binary_int_op(c_pyssize_t_rprimitive, val,
563+
int_tag, BinaryIntOp.AND, line)
564+
zero = self.add(LoadInt(0, line, rtype=c_pyssize_t_rprimitive))
565+
check = self.binary_int_op(bool_rprimitive, bitwise_and, zero, BinaryIntOp.EQ, line)
566+
return check
567+
568+
def compare_tagged(self, lhs: Value, rhs: Value, op: str, line: int) -> Value:
569+
"""Compare two tagged integers using given op"""
570+
op_type, c_func_desc = int_logical_op_mapping[op]
571+
result = self.alloc_temp(bool_rprimitive)
572+
short_int_block, int_block, out = BasicBlock(), BasicBlock(), BasicBlock()
573+
check = self.check_tagged_short_int(lhs, line)
574+
branch = Branch(check, short_int_block, int_block, Branch.BOOL_EXPR)
575+
branch.negated = False
576+
self.add(branch)
577+
self.activate_block(short_int_block)
578+
eq = self.binary_int_op(bool_rprimitive, lhs, rhs, op_type, line)
579+
self.add(Assign(result, eq, line))
580+
self.goto(out)
581+
self.activate_block(int_block)
582+
call = self.call_c(c_func_desc, [lhs, rhs], line)
583+
self.add(Assign(result, call, line))
584+
self.goto_and_activate(out)
585+
return result
586+
558587
def unary_op(self,
559588
lreg: Value,
560589
expr_op: str,

mypyc/primitives/int_ops.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
See also the documentation for mypyc.rtypes.int_rprimitive.
77
"""
88

9-
from mypyc.ir.ops import ERR_NEVER, ERR_MAGIC
9+
from typing import Dict, Tuple
10+
from mypyc.ir.ops import ERR_NEVER, ERR_MAGIC, BinaryIntOp
1011
from mypyc.ir.rtypes import (
1112
int_rprimitive, bool_rprimitive, float_rprimitive, object_rprimitive, short_int_rprimitive,
1213
str_rprimitive, RType
1314
)
1415
from mypyc.primitives.registry import (
1516
name_ref_op, binary_op, custom_op, simple_emit, name_emit,
16-
c_unary_op, CFunctionDescription, c_function_op, c_binary_op
17+
c_unary_op, CFunctionDescription, c_function_op, c_binary_op, c_custom_op
1718
)
1819

1920
# These int constructors produce object_rprimitives that then need to be unboxed
@@ -139,3 +140,18 @@ def int_unary_op(name: str, c_function_name: str) -> CFunctionDescription:
139140

140141

141142
int_neg_op = int_unary_op('-', 'CPyTagged_Negate')
143+
144+
# integer comparsion operation implementation related:
145+
146+
# description for equal operation on two boxed tagged integers
147+
int_equal_ = c_custom_op(
148+
arg_types=[int_rprimitive, int_rprimitive],
149+
return_type=bool_rprimitive,
150+
c_function_name='CPyTagged_IsEq_',
151+
error_kind=ERR_NEVER)
152+
153+
# provide mapping from textual op to short int's op variant and boxed int's description
154+
# note these are not complete implementations
155+
int_logical_op_mapping = {
156+
'==': (BinaryIntOp.EQ, int_equal_)
157+
} # type: Dict[str, Tuple[int, CFunctionDescription]]

mypyc/test-data/analysis.test

Lines changed: 78 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,38 +13,62 @@ def f(a):
1313
r0 :: short_int
1414
x :: int
1515
r1 :: bool
16-
r2 :: short_int
16+
r2, r3, r4 :: native_int
17+
r5, r6, r7 :: bool
18+
r8 :: short_int
1719
y :: int
18-
r3 :: short_int
20+
r9 :: short_int
1921
z :: int
20-
r4 :: None
22+
r10 :: None
2123
L0:
2224
r0 = 1
2325
x = r0
24-
r1 = CPyTagged_IsEq(x, a)
25-
if r1 goto L1 else goto L2 :: bool
26-
L1:
2726
r2 = 1
28-
y = r2
27+
r3 = x & r2
28+
r4 = 0
29+
r5 = r3 == r4
30+
if r5 goto L1 else goto L2 :: bool
31+
L1:
32+
r6 = x == a
33+
r1 = r6
2934
goto L3
3035
L2:
31-
r3 = 1
32-
z = r3
36+
r7 = CPyTagged_IsEq_(x, a)
37+
r1 = r7
3338
L3:
34-
r4 = None
35-
return r4
39+
if r1 goto L4 else goto L5 :: bool
40+
L4:
41+
r8 = 1
42+
y = r8
43+
goto L6
44+
L5:
45+
r9 = 1
46+
z = r9
47+
L6:
48+
r10 = None
49+
return r10
3650
(0, 0) {a} {a}
3751
(0, 1) {a} {a, x}
3852
(0, 2) {a, x} {a, x}
3953
(0, 3) {a, x} {a, x}
54+
(0, 4) {a, x} {a, x}
55+
(0, 5) {a, x} {a, x}
56+
(0, 6) {a, x} {a, x}
4057
(1, 0) {a, x} {a, x}
41-
(1, 1) {a, x} {a, x, y}
42-
(1, 2) {a, x, y} {a, x, y}
58+
(1, 1) {a, x} {a, r1, x}
59+
(1, 2) {a, r1, x} {a, r1, x}
4360
(2, 0) {a, x} {a, x}
44-
(2, 1) {a, x} {a, x, z}
45-
(2, 2) {a, x, z} {a, x, z}
46-
(3, 0) {a, x, y, z} {a, x, y, z}
47-
(3, 1) {a, x, y, z} {a, x, y, z}
61+
(2, 1) {a, x} {a, r1, x}
62+
(2, 2) {a, r1, x} {a, r1, x}
63+
(3, 0) {a, r1, x} {a, r1, x}
64+
(4, 0) {a, r1, x} {a, r1, x}
65+
(4, 1) {a, r1, x} {a, r1, x, y}
66+
(4, 2) {a, r1, x, y} {a, r1, x, y}
67+
(5, 0) {a, r1, x} {a, r1, x}
68+
(5, 1) {a, r1, x} {a, r1, x, z}
69+
(5, 2) {a, r1, x, z} {a, r1, x, z}
70+
(6, 0) {a, r1, x, y, z} {a, r1, x, y, z}
71+
(6, 1) {a, r1, x, y, z} {a, r1, x, y, z}
4872

4973
[case testSimple_Liveness]
5074
def f(a: int) -> int:
@@ -418,34 +442,58 @@ def f(a: int) -> int:
418442
def f(a):
419443
a :: int
420444
r0 :: bool
421-
r1 :: short_int
445+
r1, r2, r3 :: native_int
446+
r4, r5, r6 :: bool
447+
r7 :: short_int
422448
x :: int
423-
r2, r3 :: short_int
449+
r8, r9 :: short_int
424450
L0:
425-
r0 = CPyTagged_IsEq(a, a)
426-
if r0 goto L1 else goto L2 :: bool
451+
r1 = 1
452+
r2 = a & r1
453+
r3 = 0
454+
r4 = r2 == r3
455+
if r4 goto L1 else goto L2 :: bool
427456
L1:
428-
r1 = 2
429-
x = r1
430-
r2 = 1
431-
a = r2
457+
r5 = a == a
458+
r0 = r5
432459
goto L3
433460
L2:
434-
r3 = 1
435-
x = r3
461+
r6 = CPyTagged_IsEq_(a, a)
462+
r0 = r6
436463
L3:
464+
if r0 goto L4 else goto L5 :: bool
465+
L4:
466+
r7 = 2
467+
x = r7
468+
r8 = 1
469+
a = r8
470+
goto L6
471+
L5:
472+
r9 = 1
473+
x = r9
474+
L6:
437475
return x
438476
(0, 0) {a} {a}
439477
(0, 1) {a} {a}
478+
(0, 2) {a} {a}
479+
(0, 3) {a} {a}
480+
(0, 4) {a} {a}
440481
(1, 0) {a} {a}
441482
(1, 1) {a} {a}
442483
(1, 2) {a} {a}
443-
(1, 3) {a} {}
444-
(1, 4) {} {}
445484
(2, 0) {a} {a}
446485
(2, 1) {a} {a}
447486
(2, 2) {a} {a}
448-
(3, 0) {} {}
487+
(3, 0) {a} {a}
488+
(4, 0) {a} {a}
489+
(4, 1) {a} {a}
490+
(4, 2) {a} {a}
491+
(4, 3) {a} {}
492+
(4, 4) {} {}
493+
(5, 0) {a} {a}
494+
(5, 1) {a} {a}
495+
(5, 2) {a} {a}
496+
(6, 0) {} {}
449497

450498
[case testLoop_BorrowedArgument]
451499
def f(a: int) -> int:

0 commit comments

Comments
 (0)