Skip to content

Commit ffd9d1c

Browse files
authored
[mypyc] Introduce GetElementPtr (python#9260)
Related to mypyc/mypyc#741. This PR introduces GetElementPtr, which computes the address of an element in an aggregate type (currently RStruct is supported). Part of efforts to support the len and other macro-related primitives.
1 parent 7938f5d commit ffd9d1c

File tree

4 files changed

+55
-6
lines changed

4 files changed

+55
-6
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
12+
Truncate, BinaryIntOp, LoadMem, GetElementPtr
1313
)
1414

1515

@@ -211,6 +211,9 @@ def visit_binary_int_op(self, op: BinaryIntOp) -> GenAndKill:
211211
def visit_load_mem(self, op: LoadMem) -> GenAndKill:
212212
return self.visit_register_op(op)
213213

214+
def visit_get_element_ptr(self, op: GetElementPtr) -> GenAndKill:
215+
return self.visit_register_op(op)
216+
214217

215218
class DefinedVisitor(BaseAnalysisVisitor):
216219
"""Visitor for finding defined registers.

mypyc/codegen/emitfunc.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
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
15+
BinaryIntOp, LoadMem, GetElementPtr
1616
)
1717
from mypyc.ir.rtypes import (
18-
RType, RTuple, is_tagged, is_int32_rprimitive, is_int64_rprimitive
18+
RType, RTuple, is_tagged, is_int32_rprimitive, is_int64_rprimitive, RStruct
1919
)
2020
from mypyc.ir.func_ir import FuncIR, FuncDecl, FUNC_STATICMETHOD, FUNC_CLASSMETHOD
2121
from mypyc.ir.class_ir import ClassIR
@@ -471,6 +471,14 @@ def visit_load_mem(self, op: LoadMem) -> None:
471471
type = self.ctype(op.type)
472472
self.emit_line('%s = *(%s *)%s;' % (dest, type, src))
473473

474+
def visit_get_element_ptr(self, op: GetElementPtr) -> None:
475+
dest = self.reg(op)
476+
src = self.reg(op.src)
477+
# TODO: support tuple type
478+
assert isinstance(op.src_type, RStruct)
479+
assert op.field in op.src_type.names, "Invalid field name."
480+
self.emit_line('%s = &%s.%s;' % (dest, src, op.field))
481+
474482
# Helpers
475483

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

mypyc/ir/ops.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
from mypyc.ir.rtypes import (
2626
RType, RInstance, RTuple, RVoid, is_bool_rprimitive, is_int_rprimitive,
2727
is_short_int_rprimitive, is_none_rprimitive, object_rprimitive, bool_rprimitive,
28-
short_int_rprimitive, int_rprimitive, void_rtype, is_c_py_ssize_t_rprimitive
28+
short_int_rprimitive, int_rprimitive, void_rtype, is_c_py_ssize_t_rprimitive,
29+
c_pyssize_t_rprimitive
2930
)
3031
from mypyc.common import short_name
3132

@@ -1372,6 +1373,28 @@ def accept(self, visitor: 'OpVisitor[T]') -> T:
13721373
return visitor.visit_load_mem(self)
13731374

13741375

1376+
class GetElementPtr(RegisterOp):
1377+
"""Get the address of a struct element"""
1378+
error_kind = ERR_NEVER
1379+
1380+
def __init__(self, src: Value, src_type: RType, field: str, line: int = -1) -> None:
1381+
super().__init__(line)
1382+
self.type = c_pyssize_t_rprimitive
1383+
self.src = src
1384+
self.src_type = src_type
1385+
self.field = field
1386+
1387+
def sources(self) -> List[Value]:
1388+
return [self.src]
1389+
1390+
def to_str(self, env: Environment) -> str:
1391+
return env.format("%r = get_element_ptr %r %r :: %r", self, self.src,
1392+
self.field, self.src_type)
1393+
1394+
def accept(self, visitor: 'OpVisitor[T]') -> T:
1395+
return visitor.visit_get_element_ptr(self)
1396+
1397+
13751398
@trait
13761399
class OpVisitor(Generic[T]):
13771400
"""Generic visitor over ops (uses the visitor design pattern)."""
@@ -1482,6 +1505,10 @@ def visit_binary_int_op(self, op: BinaryIntOp) -> T:
14821505
def visit_load_mem(self, op: LoadMem) -> T:
14831506
raise NotImplementedError
14841507

1508+
@abstractmethod
1509+
def visit_get_element_ptr(self, op: GetElementPtr) -> T:
1510+
raise NotImplementedError
1511+
14851512

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

mypyc/test/test_emitfunc.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@
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
13+
SetAttr, Op, Value, CallC, BinaryIntOp, LoadMem, GetElementPtr
1414
)
1515
from mypyc.ir.rtypes import (
1616
RTuple, RInstance, int_rprimitive, bool_rprimitive, list_rprimitive,
1717
dict_rprimitive, object_rprimitive, c_int_rprimitive, short_int_rprimitive, int32_rprimitive,
18-
int64_rprimitive
18+
int64_rprimitive, StructInfo, RStruct
1919
)
2020
from mypyc.ir.func_ir import FuncIR, FuncDecl, RuntimeArg, FuncSignature
2121
from mypyc.ir.class_ir import ClassIR
@@ -282,6 +282,17 @@ def test_load_mem(self) -> None:
282282
self.assert_emit(LoadMem(bool_rprimitive, self.i64),
283283
"""cpy_r_r0 = *(char *)cpy_r_i64;""")
284284

285+
def test_get_element_ptr(self) -> None:
286+
info = StructInfo("Foo", ["b", "i32", "i64"], [bool_rprimitive,
287+
int32_rprimitive, int64_rprimitive])
288+
r = RStruct(info)
289+
self.assert_emit(GetElementPtr(self.o, r, "b"),
290+
"""cpy_r_r0 = &cpy_r_o.b;""")
291+
self.assert_emit(GetElementPtr(self.o, r, "i32"),
292+
"""cpy_r_r00 = &cpy_r_o.i32;""")
293+
self.assert_emit(GetElementPtr(self.o, r, "i64"),
294+
"""cpy_r_r01 = &cpy_r_o.i64;""")
295+
285296
def assert_emit(self, op: Op, expected: str) -> None:
286297
self.emitter.fragments = []
287298
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