Skip to content

Commit

Permalink
[mypyc] Cleanup old style primitive code (#9699)
Browse files Browse the repository at this point in the history
We have moved all the existing ops into the new IR, so this PR removes the 
old PrimitiveOp and related code.

Relates to mypyc/mypyc#709, closes mypyc/mypyc#753
  • Loading branch information
TH3CHARLie authored Nov 4, 2020
1 parent 613c0ce commit 2695e95
Show file tree
Hide file tree
Showing 7 changed files with 9 additions and 275 deletions.
5 changes: 1 addition & 4 deletions mypyc/analysis/dataflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
Value, ControlOp,
BasicBlock, OpVisitor, Assign, LoadInt, LoadErrorValue, RegisterOp, Goto, Branch, Return, Call,
Environment, Box, Unbox, Cast, Op, Unreachable, TupleGet, TupleSet, GetAttr, SetAttr,
LoadStatic, InitStatic, PrimitiveOp, MethodCall, RaiseStandardError, CallC, LoadGlobal,
LoadStatic, InitStatic, MethodCall, RaiseStandardError, CallC, LoadGlobal,
Truncate, BinaryIntOp, LoadMem, GetElementPtr, LoadAddress, ComparisonOp, SetMem
)

Expand Down Expand Up @@ -161,9 +161,6 @@ def visit_call(self, op: Call) -> GenAndKill:
def visit_method_call(self, op: MethodCall) -> GenAndKill:
return self.visit_register_op(op)

def visit_primitive_op(self, op: PrimitiveOp) -> GenAndKill:
return self.visit_register_op(op)

def visit_load_int(self, op: LoadInt) -> GenAndKill:
return self.visit_register_op(op)

Expand Down
13 changes: 1 addition & 12 deletions mypyc/codegen/emitfunc.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from mypyc.ir.ops import (
OpVisitor, Goto, Branch, Return, Assign, LoadInt, LoadErrorValue, GetAttr, SetAttr,
LoadStatic, InitStatic, TupleGet, TupleSet, Call, IncRef, DecRef, Box, Cast, Unbox,
BasicBlock, Value, MethodCall, PrimitiveOp, EmitterInterface, Unreachable, NAMESPACE_STATIC,
BasicBlock, Value, MethodCall, EmitterInterface, Unreachable, NAMESPACE_STATIC,
NAMESPACE_TYPE, NAMESPACE_MODULE, RaiseStandardError, CallC, LoadGlobal, Truncate,
BinaryIntOp, LoadMem, GetElementPtr, LoadAddress, ComparisonOp, SetMem, Register
)
Expand Down Expand Up @@ -152,17 +152,6 @@ def visit_return(self, op: Return) -> None:
regstr = self.reg(op.reg)
self.emit_line('return %s;' % regstr)

def visit_primitive_op(self, op: PrimitiveOp) -> None:
args = [self.reg(arg) for arg in op.args]
if not op.is_void:
dest = self.reg(op)
else:
# This will generate a C compile error if used. The reason for this
# is that we don't want to insert "assert dest is not None" checks
# everywhere.
dest = '<undefined dest>'
op.desc.emit(self, args, dest)

def visit_tuple_set(self, op: TupleSet) -> None:
dest = self.reg(op)
tuple_type = op.tuple_type
Expand Down
81 changes: 1 addition & 80 deletions mypyc/ir/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from abc import abstractmethod
from typing import (
List, Sequence, Dict, Generic, TypeVar, Optional, Any, NamedTuple, Tuple, Callable,
List, Sequence, Dict, Generic, TypeVar, Optional, Any, NamedTuple, Tuple,
Union, Iterable, Set
)
from mypy.ordered_dict import OrderedDict
Expand Down Expand Up @@ -693,84 +693,9 @@ def emit_declaration(self, line: str) -> None:
raise NotImplementedError


EmitCallback = Callable[[EmitterInterface, List[str], str], None]

# True steals all arguments, False steals none, a list steals those in matching positions
StealsDescription = Union[bool, List[bool]]

# Description of a primitive operation
OpDescription = NamedTuple(
'OpDescription', [('name', str),
('arg_types', List[RType]),
('result_type', Optional[RType]),
('is_var_arg', bool),
('error_kind', int),
('format_str', str),
('emit', EmitCallback),
('steals', StealsDescription),
('is_borrowed', bool),
('priority', int)]) # To resolve ambiguities, highest priority wins


class PrimitiveOp(RegisterOp):
"""reg = op(reg, ...)
These are register-based primitive operations that work on specific
operand types.
The details of the operation are defined by the 'desc'
attribute. The modules under mypyc.primitives define the supported
operations. mypyc.irbuild uses the descriptions to look for suitable
primitive ops.
"""

def __init__(self,
args: List[Value],
desc: OpDescription,
line: int) -> None:
if not desc.is_var_arg:
assert len(args) == len(desc.arg_types)
self.error_kind = desc.error_kind
super().__init__(line)
self.args = args
self.desc = desc
if desc.result_type is None:
assert desc.error_kind == ERR_FALSE # TODO: No-value ops not supported yet
self.type = bool_rprimitive
else:
self.type = desc.result_type

self.is_borrowed = desc.is_borrowed

def sources(self) -> List[Value]:
return list(self.args)

def stolen(self) -> List[Value]:
if isinstance(self.desc.steals, list):
assert len(self.desc.steals) == len(self.args)
return [arg for arg, steal in zip(self.args, self.desc.steals) if steal]
else:
return [] if not self.desc.steals else self.sources()

def __repr__(self) -> str:
return '<PrimitiveOp name=%r args=%s>' % (self.desc.name,
self.args)

def to_str(self, env: Environment) -> str:
params = {} # type: Dict[str, Any]
if not self.is_void:
params['dest'] = env.format('%r', self)
args = [env.format('%r', arg) for arg in self.args]
params['args'] = args
params['comma_args'] = ', '.join(args)
params['colon_args'] = ', '.join(
'{}: {}'.format(k, v) for k, v in zip(args[::2], args[1::2])
)
return self.desc.format_str.format(**params).strip()

def accept(self, visitor: 'OpVisitor[T]') -> T:
return visitor.visit_primitive_op(self)


class Assign(Op):
"""Assign a value to a register (dest = int)."""
Expand Down Expand Up @@ -1555,10 +1480,6 @@ def visit_return(self, op: Return) -> T:
def visit_unreachable(self, op: Unreachable) -> T:
raise NotImplementedError

@abstractmethod
def visit_primitive_op(self, op: PrimitiveOp) -> T:
raise NotImplementedError

@abstractmethod
def visit_assign(self, op: Assign) -> T:
raise NotImplementedError
Expand Down
13 changes: 2 additions & 11 deletions mypyc/irbuild/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
BasicBlock, AssignmentTarget, AssignmentTargetRegister, AssignmentTargetIndex,
AssignmentTargetAttr, AssignmentTargetTuple, Environment, LoadInt, Value,
Register, Op, Assign, Branch, Unreachable, TupleGet, GetAttr, SetAttr, LoadStatic,
InitStatic, OpDescription, NAMESPACE_MODULE, RaiseStandardError,
InitStatic, NAMESPACE_MODULE, RaiseStandardError,
)
from mypyc.ir.rtypes import (
RType, RTuple, RInstance, int_rprimitive, dict_rprimitive,
Expand All @@ -43,7 +43,7 @@
)
from mypyc.ir.func_ir import FuncIR, INVALID_FUNC_DEF
from mypyc.ir.class_ir import ClassIR, NonExtClassInfo
from mypyc.primitives.registry import func_ops, CFunctionDescription, c_function_ops
from mypyc.primitives.registry import CFunctionDescription, c_function_ops
from mypyc.primitives.list_ops import to_list, list_pop_last
from mypyc.primitives.dict_ops import dict_get_item_op, dict_set_item_op
from mypyc.primitives.generic_ops import py_setattr_op, iter_op, next_op
Expand Down Expand Up @@ -188,9 +188,6 @@ def load_static_unicode(self, value: str) -> Value:
def load_static_int(self, value: int) -> Value:
return self.builder.load_static_int(value)

def primitive_op(self, desc: OpDescription, args: List[Value], line: int) -> Value:
return self.builder.primitive_op(desc, args, line)

def unary_op(self, lreg: Value, expr_op: str, line: int) -> Value:
return self.builder.unary_op(lreg, expr_op, line)

Expand Down Expand Up @@ -763,12 +760,6 @@ def call_refexpr_with_args(
expr.line, self.node_type(expr))
if target:
return target
ops = func_ops.get(callee.fullname, [])
target = self.builder.matching_primitive_op(
ops, arg_values, expr.line, self.node_type(expr)
)
if target:
return target

# Standard native call if signature and fullname are good and all arguments are positional
# or named.
Expand Down
56 changes: 2 additions & 54 deletions mypyc/irbuild/ll_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from mypyc.ir.ops import (
BasicBlock, Environment, Op, LoadInt, Value, Register,
Assign, Branch, Goto, Call, Box, Unbox, Cast, GetAttr,
LoadStatic, MethodCall, PrimitiveOp, OpDescription, RegisterOp, CallC, Truncate,
LoadStatic, MethodCall, RegisterOp, CallC, Truncate,
RaiseStandardError, Unreachable, LoadErrorValue, LoadGlobal,
NAMESPACE_TYPE, NAMESPACE_MODULE, NAMESPACE_STATIC, BinaryIntOp, GetElementPtr,
LoadMem, ComparisonOp, LoadAddress, TupleGet, SetMem, ERR_NEVER, ERR_FALSE
Expand All @@ -39,7 +39,7 @@
STATIC_PREFIX, PLATFORM_SIZE
)
from mypyc.primitives.registry import (
func_ops, c_method_call_ops, CFunctionDescription, c_function_ops,
c_method_call_ops, CFunctionDescription, c_function_ops,
c_binary_ops, c_unary_ops, ERR_NEG_INT
)
from mypyc.primitives.list_ops import (
Expand Down Expand Up @@ -513,48 +513,6 @@ def load_native_type_object(self, fullname: str) -> Value:
return self.add(LoadStatic(object_rprimitive, name, module, NAMESPACE_TYPE))

# Other primitive operations

def primitive_op(self, desc: OpDescription, args: List[Value], line: int) -> Value:
assert desc.result_type is not None
coerced = []
for i, arg in enumerate(args):
formal_type = self.op_arg_type(desc, i)
arg = self.coerce(arg, formal_type, line)
coerced.append(arg)
target = self.add(PrimitiveOp(coerced, desc, line))
return target

def matching_primitive_op(self,
candidates: List[OpDescription],
args: List[Value],
line: int,
result_type: Optional[RType] = None) -> Optional[Value]:
# Find the highest-priority primitive op that matches.
matching = None # type: Optional[OpDescription]
for desc in candidates:
if len(desc.arg_types) != len(args):
continue
if all(is_subtype(actual.type, formal)
for actual, formal in zip(args, desc.arg_types)):
if matching:
assert matching.priority != desc.priority, 'Ambiguous:\n1) %s\n2) %s' % (
matching, desc)
if desc.priority > matching.priority:
matching = desc
else:
matching = desc
if matching:
target = self.primitive_op(matching, args, line)
if result_type and not is_runtime_subtype(target.type, result_type):
if is_none_rprimitive(result_type):
# Special case None return. The actual result may actually be a bool
# and so we can't just coerce it.
target = self.none()
else:
target = self.coerce(target, result_type, line)
return target
return None

def binary_op(self,
lreg: Value,
rreg: Value,
Expand Down Expand Up @@ -857,10 +815,6 @@ def builtin_call(self,
line: int) -> Value:
call_c_ops_candidates = c_function_ops.get(fn_op, [])
target = self.matching_call_c(call_c_ops_candidates, args, line)
if target:
return target
ops = func_ops.get(fn_op, [])
target = self.matching_primitive_op(ops, args, line)
assert target, 'Unsupported builtin function: %s' % fn_op
return target

Expand Down Expand Up @@ -1113,12 +1067,6 @@ def decompose_union_helper(self,
self.activate_block(exit_block)
return result

def op_arg_type(self, desc: OpDescription, n: int) -> RType:
if n >= len(desc.arg_types):
assert desc.is_var_arg
return desc.arg_types[-1]
return desc.arg_types[n]

def translate_special_method_call(self,
base_reg: Value,
name: str,
Expand Down
12 changes: 1 addition & 11 deletions mypyc/primitives/list_ops.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
"""List primitive ops."""

from typing import List

from mypyc.ir.ops import ERR_MAGIC, ERR_NEVER, ERR_FALSE, EmitterInterface
from mypyc.ir.ops import ERR_MAGIC, ERR_NEVER, ERR_FALSE
from mypyc.ir.rtypes import (
int_rprimitive, short_int_rprimitive, list_rprimitive, object_rprimitive, c_int_rprimitive,
c_pyssize_t_rprimitive, bit_rprimitive
Expand Down Expand Up @@ -122,14 +120,6 @@
c_function_name='CPySequence_RMultiply',
error_kind=ERR_MAGIC)


def emit_len(emitter: EmitterInterface, args: List[str], dest: str) -> None:
temp = emitter.temp_name()
emitter.emit_declaration('Py_ssize_t %s;' % temp)
emitter.emit_line('%s = PyList_GET_SIZE(%s);' % (temp, args[0]))
emitter.emit_line('%s = CPyTagged_ShortFromSsize_t(%s);' % (dest, temp))


# list[begin:end]
list_slice_op = c_custom_op(
arg_types=[list_rprimitive, int_rprimitive, int_rprimitive],
Expand Down
Loading

0 comments on commit 2695e95

Please sign in to comment.