Skip to content

Commit c1f1f95

Browse files
authored
Support binary ops via CallC (#8929)
related mypyc/mypyc#709, mypyc/mypyc#734 * support binary ops, implement str += * support list * int, int * list
1 parent 8457e50 commit c1f1f95

File tree

5 files changed

+44
-24
lines changed

5 files changed

+44
-24
lines changed

mypyc/irbuild/ll_builder.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
)
3535
from mypyc.primitives.registry import (
3636
binary_ops, unary_ops, method_ops, func_ops,
37-
c_method_call_ops, CFunctionDescription, c_function_ops
37+
c_method_call_ops, CFunctionDescription, c_function_ops,
38+
c_binary_ops
3839
)
3940
from mypyc.primitives.list_ops import (
4041
list_extend_op, list_len_op, new_list_op
@@ -541,6 +542,10 @@ def binary_op(self,
541542
if value is not None:
542543
return value
543544

545+
call_c_ops_candidates = c_binary_ops.get(expr_op, [])
546+
target = self.matching_call_c(call_c_ops_candidates, [lreg, rreg], line)
547+
if target:
548+
return target
544549
ops = binary_ops.get(expr_op, [])
545550
target = self.matching_primitive_op(ops, [lreg, rreg], line)
546551
assert target, 'Unsupported binary operation: %s' % expr_op

mypyc/primitives/list_ops.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
int_rprimitive, short_int_rprimitive, list_rprimitive, object_rprimitive, bool_rprimitive
88
)
99
from mypyc.primitives.registry import (
10-
name_ref_op, binary_op, func_op, method_op, custom_op, name_emit,
11-
call_emit, call_negative_bool_emit, c_function_op
10+
name_ref_op, func_op, method_op, custom_op, name_emit,
11+
call_emit, call_negative_bool_emit, c_function_op, c_binary_op
1212
)
1313

1414

@@ -125,20 +125,18 @@ def emit_new(emitter: EmitterInterface, args: List[str], dest: str) -> None:
125125
emit=call_emit('CPyList_Count'))
126126

127127
# list * int
128-
binary_op(op='*',
129-
arg_types=[list_rprimitive, int_rprimitive],
130-
result_type=list_rprimitive,
131-
error_kind=ERR_MAGIC,
132-
format_str='{dest} = {args[0]} * {args[1]} :: list',
133-
emit=call_emit("CPySequence_Multiply"))
128+
c_binary_op(name='*',
129+
arg_types=[list_rprimitive, int_rprimitive],
130+
return_type=list_rprimitive,
131+
c_function_name='CPySequence_Multiply',
132+
error_kind=ERR_MAGIC)
134133

135134
# int * list
136-
binary_op(op='*',
137-
arg_types=[int_rprimitive, list_rprimitive],
138-
result_type=list_rprimitive,
139-
error_kind=ERR_MAGIC,
140-
format_str='{dest} = {args[0]} * {args[1]} :: list',
141-
emit=call_emit("CPySequence_RMultiply"))
135+
c_binary_op(name='*',
136+
arg_types=[int_rprimitive, list_rprimitive],
137+
return_type=list_rprimitive,
138+
c_function_name='CPySequence_RMultiply',
139+
error_kind=ERR_MAGIC)
142140

143141

144142
def emit_len(emitter: EmitterInterface, args: List[str], dest: str) -> None:

mypyc/primitives/registry.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@
7272
# CallC op for top level function call(such as 'builtins.list')
7373
c_function_ops = {} # type: Dict[str, List[CFunctionDescription]]
7474

75+
# CallC op for binary ops
76+
c_binary_ops = {} # type: Dict[str, List[CFunctionDescription]]
77+
7578

7679
def simple_emit(template: str) -> EmitCallback:
7780
"""Construct a simple PrimitiveOp emit callback function.
@@ -354,6 +357,20 @@ def c_function_op(name: str,
354357
return desc
355358

356359

360+
def c_binary_op(name: str,
361+
arg_types: List[RType],
362+
return_type: RType,
363+
c_function_name: str,
364+
error_kind: int,
365+
steals: StealsDescription = False,
366+
priority: int = 1) -> CFunctionDescription:
367+
ops = c_binary_ops.setdefault(name, [])
368+
desc = CFunctionDescription(name, arg_types, return_type,
369+
c_function_name, error_kind, steals, priority)
370+
ops.append(desc)
371+
return desc
372+
373+
357374
# Import various modules that set up global state.
358375
import mypyc.primitives.int_ops # noqa
359376
import mypyc.primitives.str_ops # noqa

mypyc/primitives/str_ops.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
)
99
from mypyc.primitives.registry import (
1010
func_op, binary_op, simple_emit, name_ref_op, method_op, call_emit, name_emit,
11-
c_method_op
11+
c_method_op, c_binary_op
1212
)
1313

1414

@@ -68,12 +68,12 @@
6868
#
6969
# PyUnicodeAppend makes an effort to reuse the LHS when the refcount
7070
# is 1. This is super dodgy but oh well, the interpreter does it.
71-
binary_op(op='+=',
72-
arg_types=[str_rprimitive, str_rprimitive],
73-
steals=[True, False],
74-
result_type=str_rprimitive,
75-
error_kind=ERR_MAGIC,
76-
emit=call_emit('CPyStr_Append'))
71+
c_binary_op(name='+=',
72+
arg_types=[str_rprimitive, str_rprimitive],
73+
return_type=str_rprimitive,
74+
c_function_name='CPyStr_Append',
75+
error_kind=ERR_MAGIC,
76+
steals=[True, False])
7777

7878

7979
def emit_str_compare(comparison: str) -> Callable[[EmitterInterface, List[str], str], None]:

mypyc/test-data/irbuild-lists.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,13 @@ def f(a):
121121
r7 :: None
122122
L0:
123123
r0 = 2
124-
r1 = a * r0 :: list
124+
r1 = CPySequence_Multiply(a, r0)
125125
b = r1
126126
r2 = 3
127127
r3 = 4
128128
r4 = box(short_int, r3)
129129
r5 = [r4]
130-
r6 = r2 * r5 :: list
130+
r6 = CPySequence_RMultiply(r2, r5)
131131
b = r6
132132
r7 = None
133133
return r7

0 commit comments

Comments
 (0)