Skip to content

Commit d94853d

Browse files
authored
[mypyc] Implement LoadAddress (python#9287)
This PR introduces LoadAddress, an op for taking the address of a given name. Currently, in mypyc we only need to take the address of a name when we are using the name_ref_ops, so the op takes a string (CPython name) as its argument. We can revisit the design later if we want to take the address of arbitrary name later.
1 parent ab5b0ea commit d94853d

File tree

8 files changed

+70
-13
lines changed

8 files changed

+70
-13
lines changed

mypyc/analysis/dataflow.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, BinaryIntOp, LoadMem, GetElementPtr
12+
Truncate, BinaryIntOp, LoadMem, GetElementPtr, LoadAddress
1313
)
1414

1515

@@ -214,6 +214,9 @@ def visit_load_mem(self, op: LoadMem) -> GenAndKill:
214214
def visit_get_element_ptr(self, op: GetElementPtr) -> GenAndKill:
215215
return self.visit_register_op(op)
216216

217+
def visit_load_address(self, op: LoadAddress) -> GenAndKill:
218+
return self.visit_register_op(op)
219+
217220

218221
class DefinedVisitor(BaseAnalysisVisitor):
219222
"""Visitor for finding defined registers.

mypyc/codegen/emitfunc.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
LoadStatic, InitStatic, TupleGet, TupleSet, Call, IncRef, DecRef, Box, Cast, Unbox,
1313
BasicBlock, Value, MethodCall, PrimitiveOp, EmitterInterface, Unreachable, NAMESPACE_STATIC,
1414
NAMESPACE_TYPE, NAMESPACE_MODULE, RaiseStandardError, CallC, LoadGlobal, Truncate,
15-
BinaryIntOp, LoadMem, GetElementPtr
15+
BinaryIntOp, LoadMem, GetElementPtr, LoadAddress
1616
)
1717
from mypyc.ir.rtypes import (
1818
RType, RTuple, is_tagged, is_int32_rprimitive, is_int64_rprimitive, RStruct
@@ -480,6 +480,11 @@ def visit_get_element_ptr(self, op: GetElementPtr) -> None:
480480
self.emit_line('%s = (%s)&((%s *)%s)->%s;' % (dest, op.type._ctype, op.src_type.name,
481481
src, op.field))
482482

483+
def visit_load_address(self, op: LoadAddress) -> None:
484+
typ = op.type
485+
dest = self.reg(op)
486+
self.emit_line('%s = (%s)&%s;' % (dest, typ._ctype, op.src))
487+
483488
# Helpers
484489

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

mypyc/ir/ops.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,6 +1394,25 @@ def accept(self, visitor: 'OpVisitor[T]') -> T:
13941394
return visitor.visit_get_element_ptr(self)
13951395

13961396

1397+
class LoadAddress(RegisterOp):
1398+
error_kind = ERR_NEVER
1399+
is_borrowed = True
1400+
1401+
def __init__(self, type: RType, src: str, line: int = -1) -> None:
1402+
super().__init__(line)
1403+
self.type = type
1404+
self.src = src
1405+
1406+
def sources(self) -> List[Value]:
1407+
return []
1408+
1409+
def to_str(self, env: Environment) -> str:
1410+
return env.format("%r = load_address %s", self, self.src)
1411+
1412+
def accept(self, visitor: 'OpVisitor[T]') -> T:
1413+
return visitor.visit_load_address(self)
1414+
1415+
13971416
@trait
13981417
class OpVisitor(Generic[T]):
13991418
"""Generic visitor over ops (uses the visitor design pattern)."""
@@ -1508,6 +1527,10 @@ def visit_load_mem(self, op: LoadMem) -> T:
15081527
def visit_get_element_ptr(self, op: GetElementPtr) -> T:
15091528
raise NotImplementedError
15101529

1530+
@abstractmethod
1531+
def visit_load_address(self, op: LoadAddress) -> T:
1532+
raise NotImplementedError
1533+
15111534

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

mypyc/irbuild/expression.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616
from mypy.types import TupleType, get_proper_type
1717

1818
from mypyc.ir.ops import (
19-
Value, TupleGet, TupleSet, PrimitiveOp, BasicBlock, OpDescription, Assign
19+
Value, TupleGet, TupleSet, PrimitiveOp, BasicBlock, OpDescription, Assign, LoadAddress
2020
)
2121
from mypyc.ir.rtypes import RTuple, object_rprimitive, is_none_rprimitive, is_int_rprimitive
2222
from mypyc.ir.func_ir import FUNC_CLASSMETHOD, FUNC_STATICMETHOD
23-
from mypyc.primitives.registry import name_ref_ops, CFunctionDescription
23+
from mypyc.primitives.registry import name_ref_ops, CFunctionDescription, builtin_names
2424
from mypyc.primitives.generic_ops import iter_op
2525
from mypyc.primitives.misc_ops import new_slice_op, ellipsis_op, type_op
2626
from mypyc.primitives.list_ops import new_list_op, list_append_op, list_extend_op
@@ -39,6 +39,9 @@
3939
def transform_name_expr(builder: IRBuilder, expr: NameExpr) -> Value:
4040
assert expr.node, "RefExpr not resolved"
4141
fullname = expr.node.fullname
42+
if fullname in builtin_names:
43+
typ, src = builtin_names[fullname]
44+
return builder.add(LoadAddress(typ, src, expr.line))
4245
if fullname in name_ref_ops:
4346
# Use special access op for this particular name.
4447
desc = name_ref_ops[fullname]

mypyc/primitives/dict_ops.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,14 @@
88
)
99

1010
from mypyc.primitives.registry import (
11-
name_ref_op, method_op,
12-
simple_emit, name_emit, c_custom_op, c_method_op, c_function_op, c_binary_op
11+
method_op, simple_emit, c_custom_op, c_method_op, c_function_op, c_binary_op, load_address_op
1312
)
1413

15-
1614
# Get the 'dict' type object.
17-
name_ref_op('builtins.dict',
18-
result_type=object_rprimitive,
19-
error_kind=ERR_NEVER,
20-
emit=name_emit('&PyDict_Type', target_type="PyObject *"),
21-
is_borrowed=True)
15+
load_address_op(
16+
name='builtins.dict',
17+
type=object_rprimitive,
18+
src='PyDict_Type')
2219

2320
# dict[key]
2421
dict_get_item_op = c_method_op(

mypyc/primitives/registry.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@
9393
# LoadGlobal/LoadAddress op for reading global names
9494
c_name_ref_ops = {} # type: Dict[str, CLoadDescription]
9595

96+
builtin_names = {} # type: Dict[str, Tuple[RType, str]]
97+
9698

9799
def simple_emit(template: str) -> EmitCallback:
98100
"""Construct a simple PrimitiveOp emit callback function.
@@ -498,6 +500,14 @@ def c_name_ref_op(name: str,
498500
c_name_ref_ops[name] = desc
499501
return desc
500502

503+
504+
def load_address_op(name: str,
505+
type: RType,
506+
src: str) -> None:
507+
assert name not in builtin_names, 'already defined: %s' % name
508+
builtin_names[name] = (type, src)
509+
510+
501511
# Import various modules that set up global state.
502512
import mypyc.primitives.int_ops # noqa
503513
import mypyc.primitives.str_ops # noqa

mypyc/test-data/irbuild-dict.test

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,3 +306,15 @@ L12:
306306
r34 = None
307307
return r34
308308

309+
[case testDictLoadAddress]
310+
def f() -> None:
311+
x = dict
312+
[out]
313+
def f():
314+
r0, x :: object
315+
r1 :: None
316+
L0:
317+
r0 = load_address PyDict_Type
318+
x = r0
319+
r1 = None
320+
return r1

mypyc/test/test_emitfunc.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from mypyc.ir.ops import (
1111
Environment, BasicBlock, Goto, Return, LoadInt, Assign, IncRef, DecRef, Branch,
1212
Call, Unbox, Box, TupleGet, GetAttr, PrimitiveOp, RegisterOp,
13-
SetAttr, Op, Value, CallC, BinaryIntOp, LoadMem, GetElementPtr
13+
SetAttr, Op, Value, CallC, BinaryIntOp, LoadMem, GetElementPtr, LoadAddress
1414
)
1515
from mypyc.ir.rtypes import (
1616
RTuple, RInstance, int_rprimitive, bool_rprimitive, list_rprimitive,
@@ -281,6 +281,10 @@ def test_get_element_ptr(self) -> None:
281281
self.assert_emit(GetElementPtr(self.o, r, "i64"),
282282
"""cpy_r_r01 = (CPyPtr)&((Foo *)cpy_r_o)->i64;""")
283283

284+
def test_load_address(self) -> None:
285+
self.assert_emit(LoadAddress(object_rprimitive, "PyDict_Type"),
286+
"""cpy_r_r0 = (PyObject *)&PyDict_Type;""")
287+
284288
def assert_emit(self, op: Op, expected: str) -> None:
285289
self.emitter.fragments = []
286290
self.declarations.fragments = []

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy