Skip to content

Commit

Permalink
[mypyc] Merge yield_from_except_op (#9660)
Browse files Browse the repository at this point in the history
relates mypyc/mypyc#753

This PR merges yield_from_except_op into the new IR, including several changes:

A change to C wrapper's signature since the new IR currently has no unified way to represent the address of a pointer.
A change to LoadAddress, allowing it to load local reg's address.
A change to uninit pass, suppressing checks on LoadAddress
  • Loading branch information
TH3CHARLie authored Nov 4, 2020
1 parent 6bd40b8 commit 34dc670
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 23 deletions.
5 changes: 3 additions & 2 deletions mypyc/codegen/emitfunc.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
LoadStatic, InitStatic, TupleGet, TupleSet, Call, IncRef, DecRef, Box, Cast, Unbox,
BasicBlock, Value, MethodCall, PrimitiveOp, EmitterInterface, Unreachable, NAMESPACE_STATIC,
NAMESPACE_TYPE, NAMESPACE_MODULE, RaiseStandardError, CallC, LoadGlobal, Truncate,
BinaryIntOp, LoadMem, GetElementPtr, LoadAddress, ComparisonOp, SetMem
BinaryIntOp, LoadMem, GetElementPtr, LoadAddress, ComparisonOp, SetMem, Register
)
from mypyc.ir.rtypes import (
RType, RTuple, is_tagged, is_int32_rprimitive, is_int64_rprimitive, RStruct,
Expand Down Expand Up @@ -496,7 +496,8 @@ def visit_get_element_ptr(self, op: GetElementPtr) -> None:
def visit_load_address(self, op: LoadAddress) -> None:
typ = op.type
dest = self.reg(op)
self.emit_line('%s = (%s)&%s;' % (dest, typ._ctype, op.src))
src = self.reg(op.src) if isinstance(op.src, Register) else op.src
self.emit_line('%s = (%s)&%s;' % (dest, typ._ctype, src))

# Helpers

Expand Down
21 changes: 18 additions & 3 deletions mypyc/ir/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -1502,19 +1502,34 @@ def accept(self, visitor: 'OpVisitor[T]') -> T:


class LoadAddress(RegisterOp):
"""Get the address of a value
ret = (type)&src
Attributes:
type: Type of the loaded address(e.g. ptr/object_ptr)
src: Source value, str for named constants like 'PyList_Type',
Register for temporary values
"""
error_kind = ERR_NEVER
is_borrowed = True

def __init__(self, type: RType, src: str, line: int = -1) -> None:
def __init__(self, type: RType, src: Union[str, Register], line: int = -1) -> None:
super().__init__(line)
self.type = type
self.src = src

def sources(self) -> List[Value]:
return []
if isinstance(self.src, Register):
return [self.src]
else:
return []

def to_str(self, env: Environment) -> str:
return env.format("%r = load_address %s", self, self.src)
if isinstance(self.src, Register):
return env.format("%r = load_address %r", self, self.src)
else:
return env.format("%r = load_address %s", self, self.src)

def accept(self, visitor: 'OpVisitor[T]') -> T:
return visitor.visit_load_address(self)
Expand Down
6 changes: 6 additions & 0 deletions mypyc/ir/rtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ def __init__(self,
self.c_undefined = 'NULL'
elif ctype == 'char':
self.c_undefined = '2'
elif ctype == 'PyObject **':
self.c_undefined = 'NULL'
else:
assert False, 'Unrecognized ctype: %r' % ctype

Expand Down Expand Up @@ -223,6 +225,10 @@ def __repr__(self) -> str:
object_rprimitive = RPrimitive('builtins.object', is_unboxed=False,
is_refcounted=True) # type: Final

# represents a low level pointer of an object
object_pointer_rprimitive = RPrimitive('object_ptr', is_unboxed=False,
is_refcounted=False, ctype='PyObject **') # type: Final

# Arbitrary-precision integer (corresponds to Python 'int'). Small
# enough values are stored unboxed, while large integers are
# represented as a tagged pointer to a Python 'int' PyObject. The
Expand Down
11 changes: 6 additions & 5 deletions mypyc/irbuild/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@

from mypyc.ir.ops import (
BasicBlock, Value, Return, SetAttr, LoadInt, Environment, GetAttr, Branch, AssignmentTarget,
TupleGet, InitStatic
InitStatic, LoadAddress
)
from mypyc.ir.rtypes import object_rprimitive, RInstance
from mypyc.ir.rtypes import object_rprimitive, RInstance, object_pointer_rprimitive
from mypyc.ir.func_ir import (
FuncIR, FuncSignature, RuntimeArg, FuncDecl, FUNC_CLASSMETHOD, FUNC_STATICMETHOD, FUNC_NORMAL
)
Expand Down Expand Up @@ -523,9 +523,10 @@ def except_body() -> None:
# The body of the except is all implemented in a C function to
# reduce how much code we need to generate. It returns a value
# indicating whether to break or yield (or raise an exception).
res = builder.primitive_op(yield_from_except_op, [builder.read(iter_reg)], o.line)
to_stop = builder.add(TupleGet(res, 0, o.line))
val = builder.add(TupleGet(res, 1, o.line))
val = builder.alloc_temp(object_rprimitive)
val_address = builder.add(LoadAddress(object_pointer_rprimitive, val))
to_stop = builder.call_c(yield_from_except_op,
[builder.read(iter_reg), val_address], o.line)

ok, stop = BasicBlock(), BasicBlock()
builder.add(Branch(to_stop, stop, ok, Branch.BOOL))
Expand Down
20 changes: 9 additions & 11 deletions mypyc/primitives/misc_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

from mypyc.ir.ops import ERR_NEVER, ERR_MAGIC, ERR_FALSE
from mypyc.ir.rtypes import (
RTuple, bool_rprimitive, object_rprimitive, str_rprimitive,
bool_rprimitive, object_rprimitive, str_rprimitive, object_pointer_rprimitive,
int_rprimitive, dict_rprimitive, c_int_rprimitive, bit_rprimitive
)
from mypyc.primitives.registry import (
simple_emit, custom_op, c_function_op, c_custom_op, load_address_op, ERR_NEG_INT
c_function_op, c_custom_op, load_address_op, ERR_NEG_INT
)


Expand Down Expand Up @@ -55,21 +55,19 @@
error_kind=ERR_NEVER)

# This is sort of unfortunate but oh well: yield_from_except performs most of the
# error handling logic in `yield from` operations. It returns a bool and a value.
# error handling logic in `yield from` operations. It returns a bool and passes
# a value by address.
# If the bool is true, then a StopIteration was received and we should return.
# If the bool is false, then the value should be yielded.
# The normal case is probably that it signals an exception, which gets
# propagated.
yield_from_rtuple = RTuple([bool_rprimitive, object_rprimitive])

# Op used for "yield from" error handling.
# See comment in CPy_YieldFromErrorHandle for more information.
yield_from_except_op = custom_op(
name='yield_from_except',
arg_types=[object_rprimitive],
result_type=yield_from_rtuple,
error_kind=ERR_MAGIC,
emit=simple_emit('{dest}.f0 = CPy_YieldFromErrorHandle({args[0]}, &{dest}.f1);'))
yield_from_except_op = c_custom_op(
arg_types=[object_rprimitive, object_pointer_rprimitive],
return_type=bool_rprimitive,
c_function_name='CPy_YieldFromErrorHandle',
error_kind=ERR_MAGIC)

# Create method object from a callable object and self.
method_new_op = c_custom_op(
Expand Down
10 changes: 8 additions & 2 deletions mypyc/transform/uninit.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
AnalysisDict
)
from mypyc.ir.ops import (
BasicBlock, Branch, Value, RaiseStandardError, Unreachable, Environment, Register
BasicBlock, Branch, Value, RaiseStandardError, Unreachable, Environment, Register,
LoadAddress
)
from mypyc.ir.func_ir import FuncIR

Expand Down Expand Up @@ -44,8 +45,13 @@ def split_blocks_at_uninits(env: Environment,
# If a register operand is not guaranteed to be
# initialized is an operand to something other than a
# check that it is defined, insert a check.

# Note that for register operand in a LoadAddress op,
# we should be able to use it without initialization
# as we may need to use its address to update itself
if (isinstance(src, Register) and src not in defined
and not (isinstance(op, Branch) and op.op == Branch.IS_ERROR)):
and not (isinstance(op, Branch) and op.op == Branch.IS_ERROR)
and not isinstance(op, LoadAddress)):
new_block, error_block = BasicBlock(), BasicBlock()
new_block.error_handler = error_block.error_handler = cur_block.error_handler
new_blocks += [error_block, new_block]
Expand Down

0 comments on commit 34dc670

Please sign in to comment.