Skip to content

Commit 7697023

Browse files
authored
[mypyc] Add GetElement op and other minor ir tweaks (#20721)
The `GetElement` op gets a struct field from a struct value, unlike `GetElementPtr` which takes a pointer to a struct. These changes were extracted from mypyc vec type support branch, and aren't very useful by themselves. I'm splitting the branch into multiple PRs to simplify reviewing.
1 parent 9f157d9 commit 7697023

8 files changed

Lines changed: 73 additions & 1 deletion

File tree

mypyc/analysis/dataflow.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
FloatNeg,
2525
FloatOp,
2626
GetAttr,
27+
GetElement,
2728
GetElementPtr,
2829
Goto,
2930
IncRef,
@@ -271,6 +272,9 @@ def visit_float_comparison_op(self, op: FloatComparisonOp) -> GenAndKill[T]:
271272
def visit_load_mem(self, op: LoadMem) -> GenAndKill[T]:
272273
return self.visit_register_op(op)
273274

275+
def visit_get_element(self, op: GetElement) -> GenAndKill[T]:
276+
return self.visit_register_op(op)
277+
274278
def visit_get_element_ptr(self, op: GetElementPtr) -> GenAndKill[T]:
275279
return self.visit_register_op(op)
276280

mypyc/analysis/ircheck.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
FloatNeg,
2323
FloatOp,
2424
GetAttr,
25+
GetElement,
2526
GetElementPtr,
2627
Goto,
2728
IncRef,
@@ -449,6 +450,9 @@ def visit_load_mem(self, op: LoadMem) -> None:
449450
def visit_set_mem(self, op: SetMem) -> None:
450451
pass
451452

453+
def visit_get_element(self, op: GetElement) -> None:
454+
pass
455+
452456
def visit_get_element_ptr(self, op: GetElementPtr) -> None:
453457
pass
454458

mypyc/analysis/selfleaks.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
FloatNeg,
1717
FloatOp,
1818
GetAttr,
19+
GetElement,
1920
GetElementPtr,
2021
Goto,
2122
InitStatic,
@@ -179,6 +180,9 @@ def visit_float_comparison_op(self, op: FloatComparisonOp) -> GenAndKill:
179180
def visit_load_mem(self, op: LoadMem) -> GenAndKill:
180181
return CLEAN
181182

183+
def visit_get_element(self, op: GetElement) -> GenAndKill:
184+
return CLEAN
185+
182186
def visit_get_element_ptr(self, op: GetElementPtr) -> GenAndKill:
183187
return CLEAN
184188

mypyc/codegen/emitfunc.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
FloatNeg,
4343
FloatOp,
4444
GetAttr,
45+
GetElement,
4546
GetElementPtr,
4647
Goto,
4748
IncRef,
@@ -795,6 +796,12 @@ def visit_set_mem(self, op: SetMem) -> None:
795796
if dest != src:
796797
self.emit_line(f"*({dest_type} *){dest} = {src};")
797798

799+
def visit_get_element(self, op: GetElement) -> None:
800+
dest = self.reg(op)
801+
src = self.reg(op.src)
802+
dest_type = self.ctype(op.type)
803+
self.emit_line(f"{dest} = ({dest_type}){src}.{op.field};")
804+
798805
def visit_get_element_ptr(self, op: GetElementPtr) -> None:
799806
dest = self.reg(op)
800807
src = self.reg(op.src)

mypyc/ir/ops.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,8 @@ def set_sources(self, new: list[Value]) -> None:
337337
(self.src,) = new
338338

339339
def stolen(self) -> list[Value]:
340+
if not self.dest.type.is_refcounted:
341+
return []
340342
return [self.src]
341343

342344
def accept(self, visitor: OpVisitor[T]) -> T:
@@ -1679,9 +1681,36 @@ def accept(self, visitor: OpVisitor[T]) -> T:
16791681
return visitor.visit_set_mem(self)
16801682

16811683

1684+
@final
1685+
class GetElement(RegisterOp):
1686+
"""Get the value of a struct element from a struct value."""
1687+
1688+
error_kind = ERR_NEVER
1689+
is_borrowed = True
1690+
1691+
def __init__(self, src: Value, field: str, line: int = -1) -> None:
1692+
super().__init__(line)
1693+
assert isinstance(src.type, RStruct)
1694+
self.type = src.type.field_type(field)
1695+
self.src = src
1696+
self.src_type = src.type
1697+
self.field = field
1698+
1699+
def sources(self) -> list[Value]:
1700+
return [self.src]
1701+
1702+
def set_sources(self, new: list[Value]) -> None:
1703+
(self.src,) = new
1704+
1705+
def accept(self, visitor: OpVisitor[T]) -> T:
1706+
return visitor.visit_get_element(self)
1707+
1708+
16821709
@final
16831710
class GetElementPtr(RegisterOp):
1684-
"""Get the address of a struct element.
1711+
"""Get the address of a struct element from a pointer to a struct.
1712+
1713+
If you have a struct value, use GetElement instead.
16851714
16861715
Note that you may need to use KeepAlive to avoid the struct
16871716
being freed, if it's reference counted, such as PyObject *.
@@ -1691,6 +1720,7 @@ class GetElementPtr(RegisterOp):
16911720

16921721
def __init__(self, src: Value, src_type: RType, field: str, line: int = -1) -> None:
16931722
super().__init__(line)
1723+
assert not isinstance(src.type, RStruct)
16941724
self.type = pointer_rprimitive
16951725
self.src = src
16961726
self.src_type = src_type
@@ -2008,6 +2038,10 @@ def visit_load_mem(self, op: LoadMem) -> T:
20082038
def visit_set_mem(self, op: SetMem) -> T:
20092039
raise NotImplementedError
20102040

2041+
@abstractmethod
2042+
def visit_get_element(self, op: GetElement) -> T:
2043+
raise NotImplementedError
2044+
20112045
@abstractmethod
20122046
def visit_get_element_ptr(self, op: GetElementPtr) -> T:
20132047
raise NotImplementedError

mypyc/ir/pprint.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
FloatNeg,
3030
FloatOp,
3131
GetAttr,
32+
GetElement,
3233
GetElementPtr,
3334
Goto,
3435
IncRef,
@@ -280,6 +281,9 @@ def visit_load_mem(self, op: LoadMem) -> str:
280281
def visit_set_mem(self, op: SetMem) -> str:
281282
return self.format("set_mem %r, %r :: %t*", op.dest, op.src, op.dest_type)
282283

284+
def visit_get_element(self, op: GetElement) -> str:
285+
return self.format("%r = %r.%s", op, op.src, op.field)
286+
283287
def visit_get_element_ptr(self, op: GetElementPtr) -> str:
284288
return self.format("%r = get_element_ptr %r %s :: %t", op, op.src, op.field, op.src_type)
285289

mypyc/ir/rtypes.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,13 +865,21 @@ def __init__(self, name: str, names: list[str], types: list[RType]) -> None:
865865
self.name = name
866866
self.names = names
867867
self.types = types
868+
self.is_refcounted = any(t.is_refcounted for t in self.types)
869+
868870
# generate dummy names
869871
if len(self.names) < len(self.types):
870872
for i in range(len(self.types) - len(self.names)):
871873
self.names.append("_item" + str(i))
872874
self.offsets, self.size = compute_aligned_offsets_and_size(types)
873875
self._ctype = name
874876

877+
def field_type(self, name: str) -> RType:
878+
for n, t in zip(self.names, self.types):
879+
if n == name:
880+
return t
881+
assert False, f"{self.name} has no field '{name}'"
882+
875883
def accept(self, visitor: RTypeVisitor[T]) -> T:
876884
return visitor.visit_rstruct(self)
877885

mypyc/transform/ir_transform.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
FloatNeg,
2121
FloatOp,
2222
GetAttr,
23+
GetElement,
2324
GetElementPtr,
2425
Goto,
2526
IncRef,
@@ -212,6 +213,9 @@ def visit_load_mem(self, op: LoadMem) -> Value | None:
212213
def visit_set_mem(self, op: SetMem) -> Value | None:
213214
return self.add(op)
214215

216+
def visit_get_element(self, op: GetElement) -> Value | None:
217+
return self.add(op)
218+
215219
def visit_get_element_ptr(self, op: GetElementPtr) -> Value | None:
216220
return self.add(op)
217221

@@ -355,6 +359,9 @@ def visit_set_mem(self, op: SetMem) -> None:
355359
op.dest = self.fix_op(op.dest)
356360
op.src = self.fix_op(op.src)
357361

362+
def visit_get_element(self, op: GetElement) -> None:
363+
op.src = self.fix_op(op.src)
364+
358365
def visit_get_element_ptr(self, op: GetElementPtr) -> None:
359366
op.src = self.fix_op(op.src)
360367

0 commit comments

Comments
 (0)