Skip to content

Commit

Permalink
[mypyc] Introduce LoadMem (python#9211)
Browse files Browse the repository at this point in the history
Relates mypyc/mypyc#741

Introduce LoadMem IR to read a memory address and convert it into a 
designated-type value. (The address would mostly be in py_ssize_t for now.)

Part of efforts to implement len primitives: *(Py_ssize_t*)(ob + size_offset).
  • Loading branch information
TH3CHARLie authored Jul 28, 2020
1 parent 65186ae commit 997b5f2
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 4 deletions.
5 changes: 4 additions & 1 deletion mypyc/analysis/dataflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
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,
Truncate, BinaryIntOp
Truncate, BinaryIntOp, LoadMem
)


Expand Down Expand Up @@ -208,6 +208,9 @@ def visit_load_global(self, op: LoadGlobal) -> GenAndKill:
def visit_binary_int_op(self, op: BinaryIntOp) -> GenAndKill:
return self.visit_register_op(op)

def visit_load_mem(self, op: LoadMem) -> GenAndKill:
return self.visit_register_op(op)


class DefinedVisitor(BaseAnalysisVisitor):
"""Visitor for finding defined registers.
Expand Down
9 changes: 8 additions & 1 deletion 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
BinaryIntOp, LoadMem
)
from mypyc.ir.rtypes import (
RType, RTuple, is_tagged, is_int32_rprimitive, is_int64_rprimitive
Expand Down Expand Up @@ -464,6 +464,13 @@ def visit_binary_int_op(self, op: BinaryIntOp) -> None:
self.emit_line('%s = %s%s %s %s%s;' % (dest, lhs_cast, lhs,
op.op_str[op.op], rhs_cast, rhs))

def visit_load_mem(self, op: LoadMem) -> None:
dest = self.reg(op)
src = self.reg(op.src)
# TODO: we shouldn't dereference to type that are pointer type so far
type = self.ctype(op.type)
self.emit_line('%s = *(%s *)%s;' % (dest, type, src))

# Helpers

def label(self, label: BasicBlock) -> str:
Expand Down
31 changes: 30 additions & 1 deletion mypyc/ir/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from mypyc.ir.rtypes import (
RType, RInstance, RTuple, RVoid, is_bool_rprimitive, is_int_rprimitive,
is_short_int_rprimitive, is_none_rprimitive, object_rprimitive, bool_rprimitive,
short_int_rprimitive, int_rprimitive, void_rtype
short_int_rprimitive, int_rprimitive, void_rtype, is_c_py_ssize_t_rprimitive
)
from mypyc.common import short_name

Expand Down Expand Up @@ -1347,6 +1347,31 @@ def accept(self, visitor: 'OpVisitor[T]') -> T:
return visitor.visit_binary_int_op(self)


class LoadMem(RegisterOp):
"""Reading a memory location
type ret = *(type*)src
"""
error_kind = ERR_NEVER

def __init__(self, type: RType, src: Value, line: int = -1) -> None:
super().__init__(line)
self.type = type
# TODO: for now we enforce that the src memory address should be Py_ssize_t
# later we should also support same width unsigned int
assert is_c_py_ssize_t_rprimitive(src.type)
self.src = src

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

def to_str(self, env: Environment) -> str:
return env.format("%r = load_mem %r :: %r*", self, self.src, self.type)

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


@trait
class OpVisitor(Generic[T]):
"""Generic visitor over ops (uses the visitor design pattern)."""
Expand Down Expand Up @@ -1453,6 +1478,10 @@ def visit_load_global(self, op: LoadGlobal) -> T:
def visit_binary_int_op(self, op: BinaryIntOp) -> T:
raise NotImplementedError

@abstractmethod
def visit_load_mem(self, op: LoadMem) -> T:
raise NotImplementedError


# TODO: Should this live somewhere else?
LiteralsMap = Dict[Tuple[Type[object], Union[int, float, str, bytes, complex]], str]
Expand Down
4 changes: 4 additions & 0 deletions mypyc/ir/rtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,10 @@ def is_int64_rprimitive(rtype: RType) -> bool:
return rtype is int64_rprimitive


def is_c_py_ssize_t_rprimitive(rtype: RType) -> bool:
return rtype is c_pyssize_t_rprimitive


def is_float_rprimitive(rtype: RType) -> bool:
return isinstance(rtype, RPrimitive) and rtype.name == 'builtins.float'

Expand Down
11 changes: 10 additions & 1 deletion mypyc/test/test_emitfunc.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from mypyc.ir.ops import (
Environment, BasicBlock, Goto, Return, LoadInt, Assign, IncRef, DecRef, Branch,
Call, Unbox, Box, TupleGet, GetAttr, PrimitiveOp, RegisterOp,
SetAttr, Op, Value, CallC, BinaryIntOp
SetAttr, Op, Value, CallC, BinaryIntOp, LoadMem
)
from mypyc.ir.rtypes import (
RTuple, RInstance, int_rprimitive, bool_rprimitive, list_rprimitive,
Expand All @@ -33,6 +33,7 @@
from mypyc.primitives.int_ops import int_neg_op
from mypyc.subtype import is_subtype
from mypyc.namegen import NameGenerator
from mypyc.common import IS_32_BIT_PLATFORM


class TestFunctionEmitterVisitor(unittest.TestCase):
Expand Down Expand Up @@ -273,6 +274,14 @@ def test_binary_int_op(self) -> None:
self.assert_emit(BinaryIntOp(bool_rprimitive, self.i64, self.i64_1, BinaryIntOp.ULT, 1),
"""cpy_r_r04 = (uint64_t)cpy_r_i64 < (uint64_t)cpy_r_i64_1;""")

def test_load_mem(self) -> None:
if IS_32_BIT_PLATFORM:
self.assert_emit(LoadMem(bool_rprimitive, self.i32),
"""cpy_r_r0 = *(char *)cpy_r_i32;""")
else:
self.assert_emit(LoadMem(bool_rprimitive, self.i64),
"""cpy_r_r0 = *(char *)cpy_r_i64;""")

def assert_emit(self, op: Op, expected: str) -> None:
self.emitter.fragments = []
self.declarations.fragments = []
Expand Down

0 comments on commit 997b5f2

Please sign in to comment.