Skip to content

Commit b98c47e

Browse files
authored
[mypyc] Add BinaryIntOp for low-level integer operations (#9108)
Related: mypyc/mypyc#741 This PR introduces BinaryIntOp to represent all low-level integer binary operations. The block-like logic described in mypyc/mypyc#743 would be handled differently, BinaryIntOp would be the building block of it.
1 parent 259e0cf commit b98c47e

File tree

10 files changed

+117
-33
lines changed

10 files changed

+117
-33
lines changed

mypyc/analysis.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
BasicBlock, OpVisitor, Assign, LoadInt, LoadErrorValue, RegisterOp, Goto, Branch, Return, Call,
1010
Environment, Box, Unbox, Cast, Op, Unreachable, TupleGet, TupleSet, GetAttr, SetAttr,
1111
LoadStatic, InitStatic, PrimitiveOp, MethodCall, RaiseStandardError, CallC, LoadGlobal,
12-
Truncate
12+
Truncate, BinaryIntOp
1313
)
1414

1515

@@ -205,6 +205,9 @@ def visit_truncate(self, op: Truncate) -> GenAndKill:
205205
def visit_load_global(self, op: LoadGlobal) -> GenAndKill:
206206
return self.visit_register_op(op)
207207

208+
def visit_binary_int_op(self, op: BinaryIntOp) -> GenAndKill:
209+
return self.visit_register_op(op)
210+
208211

209212
class DefinedVisitor(BaseAnalysisVisitor):
210213
"""Visitor for finding defined registers.

mypyc/codegen/emitfunc.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
OpVisitor, Goto, Branch, Return, Assign, LoadInt, LoadErrorValue, GetAttr, SetAttr,
1212
LoadStatic, InitStatic, TupleGet, TupleSet, Call, IncRef, DecRef, Box, Cast, Unbox,
1313
BasicBlock, Value, MethodCall, PrimitiveOp, EmitterInterface, Unreachable, NAMESPACE_STATIC,
14-
NAMESPACE_TYPE, NAMESPACE_MODULE, RaiseStandardError, CallC, LoadGlobal, Truncate
14+
NAMESPACE_TYPE, NAMESPACE_MODULE, RaiseStandardError, CallC, LoadGlobal, Truncate,
15+
BinaryIntOp
1516
)
1617
from mypyc.ir.rtypes import RType, RTuple, is_int32_rprimitive, is_int64_rprimitive
1718
from mypyc.ir.func_ir import FuncIR, FuncDecl, FUNC_STATICMETHOD, FUNC_CLASSMETHOD
@@ -436,6 +437,12 @@ def visit_load_global(self, op: LoadGlobal) -> None:
436437
ann = ' /* %s */' % s
437438
self.emit_line('%s = %s;%s' % (dest, op.identifier, ann))
438439

440+
def visit_binary_int_op(self, op: BinaryIntOp) -> None:
441+
dest = self.reg(op)
442+
lhs = self.reg(op.lhs)
443+
rhs = self.reg(op.rhs)
444+
self.emit_line('%s = %s %s %s;' % (dest, lhs, op.op_str[op.op], rhs))
445+
439446
# Helpers
440447

441448
def label(self, label: BasicBlock) -> str:

mypyc/ir/ops.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,6 +1252,70 @@ def accept(self, visitor: 'OpVisitor[T]') -> T:
12521252
return visitor.visit_load_global(self)
12531253

12541254

1255+
class BinaryIntOp(RegisterOp):
1256+
"""Binary operations on integer types
1257+
1258+
These ops are low-level and will be eventually generated to simple x op y form.
1259+
The left and right values should be of low-level integer types that support those ops
1260+
"""
1261+
error_kind = ERR_NEVER
1262+
1263+
# arithmetic
1264+
ADD = 0 # type: Final
1265+
SUB = 1 # type: Final
1266+
MUL = 2 # type: Final
1267+
DIV = 3 # type: Final
1268+
MOD = 4 # type: Final
1269+
# logical
1270+
EQ = 100 # type: Final
1271+
NEQ = 101 # type: Final
1272+
LT = 102 # type: Final
1273+
GT = 103 # type: Final
1274+
LEQ = 104 # type: Final
1275+
GEQ = 105 # type: Final
1276+
# bitwise
1277+
AND = 200 # type: Final
1278+
OR = 201 # type: Final
1279+
XOR = 202 # type: Final
1280+
LEFT_SHIFT = 203 # type: Final
1281+
RIGHT_SHIFT = 204 # type: Final
1282+
1283+
op_str = {
1284+
ADD: '+',
1285+
SUB: '-',
1286+
MUL: '*',
1287+
DIV: '/',
1288+
MOD: '%',
1289+
EQ: '==',
1290+
NEQ: '!=',
1291+
LT: '<',
1292+
GT: '>',
1293+
LEQ: '<=',
1294+
GEQ: '>=',
1295+
AND: '&',
1296+
OR: '|',
1297+
XOR: '^',
1298+
LEFT_SHIFT: '<<',
1299+
RIGHT_SHIFT: '>>',
1300+
} # type: Final
1301+
1302+
def __init__(self, type: RType, lhs: Value, rhs: Value, op: int, line: int = -1) -> None:
1303+
super().__init__(line)
1304+
self.type = type
1305+
self.lhs = lhs
1306+
self.rhs = rhs
1307+
self.op = op
1308+
1309+
def sources(self) -> List[Value]:
1310+
return [self.lhs, self.rhs]
1311+
1312+
def to_str(self, env: Environment) -> str:
1313+
return env.format('%r = %r %s %r', self, self.lhs, self.op_str[self.op], self.rhs)
1314+
1315+
def accept(self, visitor: 'OpVisitor[T]') -> T:
1316+
return visitor.visit_binary_int_op(self)
1317+
1318+
12551319
@trait
12561320
class OpVisitor(Generic[T]):
12571321
"""Generic visitor over ops (uses the visitor design pattern)."""
@@ -1354,6 +1418,10 @@ def visit_truncate(self, op: Truncate) -> T:
13541418
def visit_load_global(self, op: LoadGlobal) -> T:
13551419
raise NotImplementedError
13561420

1421+
@abstractmethod
1422+
def visit_binary_int_op(self, op: BinaryIntOp) -> T:
1423+
raise NotImplementedError
1424+
13571425

13581426
# TODO: Should this live somewhere else?
13591427
LiteralsMap = Dict[Tuple[Type[object], Union[int, float, str, bytes, complex]], str]

mypyc/irbuild/builder.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ def load_module(self, name: str) -> Value:
232232
def call_c(self, desc: CFunctionDescription, args: List[Value], line: int) -> Value:
233233
return self.builder.call_c(desc, args, line)
234234

235+
def binary_int_op(self, type: RType, lhs: Value, rhs: Value, op: int, line: int) -> Value:
236+
return self.builder.binary_int_op(type, lhs, rhs, op, line)
237+
235238
@property
236239
def environment(self) -> Environment:
237240
return self.builder.environment

mypyc/irbuild/for_helpers.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,16 @@
1313
)
1414
from mypyc.ir.ops import (
1515
Value, BasicBlock, LoadInt, Branch, Register, AssignmentTarget, TupleGet,
16-
AssignmentTargetTuple, TupleSet, OpDescription
16+
AssignmentTargetTuple, TupleSet, OpDescription, BinaryIntOp
1717
)
1818
from mypyc.ir.rtypes import (
1919
RType, is_short_int_rprimitive, is_list_rprimitive, is_sequence_rprimitive,
20-
RTuple, is_dict_rprimitive
20+
RTuple, is_dict_rprimitive, short_int_rprimitive
2121
)
2222
from mypyc.primitives.dict_ops import (
2323
dict_next_key_op, dict_next_value_op, dict_next_item_op, dict_check_size_op,
2424
dict_key_iter_op, dict_value_iter_op, dict_item_iter_op
2525
)
26-
from mypyc.primitives.int_ops import unsafe_short_add
2726
from mypyc.primitives.list_ops import new_list_op, list_append_op, list_get_item_unsafe_op
2827
from mypyc.primitives.generic_ops import iter_op, next_op
2928
from mypyc.primitives.exc_ops import no_err_occurred_op
@@ -465,10 +464,10 @@ def gen_step(self) -> None:
465464
builder = self.builder
466465
line = self.line
467466
step = 1 if not self.reverse else -1
468-
builder.assign(self.index_target, builder.primitive_op(
469-
unsafe_short_add,
470-
[builder.read(self.index_target, line),
471-
builder.add(LoadInt(step))], line), line)
467+
add = builder.binary_int_op(short_int_rprimitive,
468+
builder.read(self.index_target, line),
469+
builder.add(LoadInt(step)), BinaryIntOp.ADD, line)
470+
builder.assign(self.index_target, add, line)
472471

473472

474473
class ForDictionaryCommon(ForGenerator):
@@ -635,9 +634,9 @@ def gen_step(self) -> None:
635634
# short ints.
636635
if (is_short_int_rprimitive(self.start_reg.type)
637636
and is_short_int_rprimitive(self.end_reg.type)):
638-
new_val = builder.primitive_op(
639-
unsafe_short_add, [builder.read(self.index_reg, line),
640-
builder.add(LoadInt(self.step))], line)
637+
new_val = builder.binary_int_op(short_int_rprimitive,
638+
builder.read(self.index_reg, line),
639+
builder.add(LoadInt(self.step)), BinaryIntOp.ADD, line)
641640

642641
else:
643642
new_val = builder.binary_op(
@@ -665,9 +664,9 @@ def gen_step(self) -> None:
665664
# We can safely assume that the integer is short, since we are not going to wrap
666665
# around a 63-bit integer.
667666
# NOTE: This would be questionable if short ints could be 32 bits.
668-
new_val = builder.primitive_op(
669-
unsafe_short_add, [builder.read(self.index_reg, line),
670-
builder.add(LoadInt(1))], line)
667+
new_val = builder.binary_int_op(short_int_rprimitive,
668+
builder.read(self.index_reg, line),
669+
builder.add(LoadInt(1)), BinaryIntOp.ADD, line)
671670
builder.assign(self.index_reg, new_val, line)
672671
builder.assign(self.index_target, new_val, line)
673672

mypyc/irbuild/ll_builder.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
Assign, Branch, Goto, Call, Box, Unbox, Cast, GetAttr,
2222
LoadStatic, MethodCall, PrimitiveOp, OpDescription, RegisterOp, CallC, Truncate,
2323
RaiseStandardError, Unreachable, LoadErrorValue, LoadGlobal,
24-
NAMESPACE_TYPE, NAMESPACE_MODULE, NAMESPACE_STATIC,
24+
NAMESPACE_TYPE, NAMESPACE_MODULE, NAMESPACE_STATIC, BinaryIntOp
2525
)
2626
from mypyc.ir.rtypes import (
2727
RType, RUnion, RInstance, optional_value_type, int_rprimitive, float_rprimitive,
@@ -750,6 +750,9 @@ def matching_call_c(self,
750750
return target
751751
return None
752752

753+
def binary_int_op(self, type: RType, lhs: Value, rhs: Value, op: int, line: int) -> Value:
754+
return self.add(BinaryIntOp(type, lhs, rhs, op, line))
755+
753756
# Internal helpers
754757

755758
def decompose_union_helper(self,

mypyc/test-data/irbuild-basic.test

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1917,7 +1917,7 @@ L6:
19171917
r20 = r0.append(r19) :: list
19181918
L7:
19191919
r21 = 1
1920-
r22 = r9 + r21 :: short_int
1920+
r22 = r9 + r21
19211921
r9 = r22
19221922
goto L1
19231923
L8:
@@ -1982,7 +1982,7 @@ L6:
19821982
r21 = r0.__setitem__(r19, r20) :: dict
19831983
L7:
19841984
r22 = 1
1985-
r23 = r9 + r22 :: short_int
1985+
r23 = r9 + r22
19861986
r9 = r23
19871987
goto L1
19881988
L8:
@@ -2032,7 +2032,7 @@ L2:
20322032
z = r8
20332033
L3:
20342034
r9 = 1
2035-
r10 = r1 + r9 :: short_int
2035+
r10 = r1 + r9
20362036
r1 = r10
20372037
goto L1
20382038
L4:
@@ -2058,7 +2058,7 @@ L6:
20582058
r24 = r11.append(r23) :: list
20592059
L7:
20602060
r25 = 1
2061-
r26 = r13 + r25 :: short_int
2061+
r26 = r13 + r25
20622062
r13 = r26
20632063
goto L5
20642064
L8:

mypyc/test-data/irbuild-lists.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ L2:
195195
r8 = CPyList_SetItem(l, i, r7)
196196
L3:
197197
r9 = 1
198-
r10 = r2 + r9 :: short_int
198+
r10 = r2 + r9
199199
r2 = r10
200200
i = r10
201201
goto L1

mypyc/test-data/irbuild-statements.test

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ L2:
2828
x = r5
2929
L3:
3030
r6 = 1
31-
r7 = r3 + r6 :: short_int
31+
r7 = r3 + r6
3232
r3 = r7
3333
i = r7
3434
goto L1
@@ -58,7 +58,7 @@ L1:
5858
L2:
5959
L3:
6060
r4 = -1
61-
r5 = r2 + r4 :: short_int
61+
r5 = r2 + r4
6262
r2 = r5
6363
i = r5
6464
goto L1
@@ -113,7 +113,7 @@ L2:
113113
goto L4
114114
L3:
115115
r4 = 1
116-
r5 = r2 + r4 :: short_int
116+
r5 = r2 + r4
117117
r2 = r5
118118
n = r5
119119
goto L1
@@ -202,7 +202,7 @@ L1:
202202
L2:
203203
L3:
204204
r4 = 1
205-
r5 = r2 + r4 :: short_int
205+
r5 = r2 + r4
206206
r2 = r5
207207
n = r5
208208
goto L1
@@ -281,7 +281,7 @@ L2:
281281
y = r7
282282
L3:
283283
r8 = 1
284-
r9 = r2 + r8 :: short_int
284+
r9 = r2 + r8
285285
r2 = r9
286286
goto L1
287287
L4:
@@ -868,11 +868,11 @@ L2:
868868
r8 = CPyTagged_Add(i, x)
869869
L3:
870870
r9 = 1
871-
r10 = r1 + r9 :: short_int
871+
r10 = r1 + r9
872872
r1 = r10
873873
i = r10
874874
r11 = 1
875-
r12 = r3 + r11 :: short_int
875+
r12 = r3 + r11
876876
r3 = r12
877877
goto L1
878878
L4:
@@ -901,7 +901,7 @@ L2:
901901
n = r4
902902
L3:
903903
r5 = 1
904-
r6 = r1 + r5 :: short_int
904+
r6 = r1 + r5
905905
r1 = r6
906906
i = r6
907907
goto L1
@@ -961,7 +961,7 @@ L4:
961961
L5:
962962
L6:
963963
r11 = 1
964-
r12 = r1 + r11 :: short_int
964+
r12 = r1 + r11
965965
r1 = r12
966966
goto L1
967967
L7:
@@ -1012,10 +1012,10 @@ L4:
10121012
x = r13
10131013
L5:
10141014
r14 = 1
1015-
r15 = r2 + r14 :: short_int
1015+
r15 = r2 + r14
10161016
r2 = r15
10171017
r16 = 1
1018-
r17 = r5 + r16 :: short_int
1018+
r17 = r5 + r16
10191019
r5 = r17
10201020
z = r17
10211021
goto L1
@@ -1024,3 +1024,4 @@ L6:
10241024
L7:
10251025
r19 = None
10261026
return r19
1027+

mypyc/test-data/irbuild-tuple.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ L2:
155155
x = r5
156156
L3:
157157
r6 = 1
158-
r7 = r1 + r6 :: short_int
158+
r7 = r1 + r6
159159
r1 = r7
160160
goto L1
161161
L4:

0 commit comments

Comments
 (0)