Skip to content

Commit a6ab81e

Browse files
authored
[mypyc] Implement SetMem (#9364)
This PR implements SetMem op to set value to a memory address.
1 parent a2e529a commit a6ab81e

File tree

4 files changed

+86
-3
lines changed

4 files changed

+86
-3
lines changed

mypyc/analysis/dataflow.py

Lines changed: 17 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, LoadAddress, ComparisonOp
12+
Truncate, BinaryIntOp, LoadMem, GetElementPtr, LoadAddress, ComparisonOp, SetMem
1313
)
1414

1515

@@ -151,6 +151,10 @@ def visit_register_op(self, op: RegisterOp) -> GenAndKill:
151151
def visit_assign(self, op: Assign) -> GenAndKill:
152152
raise NotImplementedError
153153

154+
@abstractmethod
155+
def visit_set_mem(self, op: SetMem) -> GenAndKill:
156+
raise NotImplementedError
157+
154158
def visit_call(self, op: Call) -> GenAndKill:
155159
return self.visit_register_op(op)
156160

@@ -248,6 +252,9 @@ def visit_assign(self, op: Assign) -> GenAndKill:
248252
else:
249253
return {op.dest}, set()
250254

255+
def visit_set_mem(self, op: SetMem) -> GenAndKill:
256+
return set(), set()
257+
251258

252259
def analyze_maybe_defined_regs(blocks: List[BasicBlock],
253260
cfg: CFG,
@@ -308,6 +315,9 @@ def visit_assign(self, op: Assign) -> GenAndKill:
308315
return set(), {op.dest}
309316
return set(), set()
310317

318+
def visit_set_mem(self, op: SetMem) -> GenAndKill:
319+
return set(), set()
320+
311321

312322
def analyze_borrowed_arguments(
313323
blocks: List[BasicBlock],
@@ -342,6 +352,9 @@ def visit_register_op(self, op: RegisterOp) -> GenAndKill:
342352
def visit_assign(self, op: Assign) -> GenAndKill:
343353
return set(), {op.dest}
344354

355+
def visit_set_mem(self, op: SetMem) -> GenAndKill:
356+
return set(), set()
357+
345358

346359
def analyze_undefined_regs(blocks: List[BasicBlock],
347360
cfg: CFG,
@@ -381,6 +394,9 @@ def visit_register_op(self, op: RegisterOp) -> GenAndKill:
381394
def visit_assign(self, op: Assign) -> GenAndKill:
382395
return set(op.sources()), {op.dest}
383396

397+
def visit_set_mem(self, op: SetMem) -> GenAndKill:
398+
return set(op.sources()), set()
399+
384400

385401
def analyze_live_regs(blocks: List[BasicBlock],
386402
cfg: CFG) -> AnalysisResult[Value]:

mypyc/codegen/emitfunc.py

Lines changed: 10 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, LoadAddress, ComparisonOp
15+
BinaryIntOp, LoadMem, GetElementPtr, LoadAddress, ComparisonOp, SetMem
1616
)
1717
from mypyc.ir.rtypes import (
1818
RType, RTuple, is_tagged, is_int32_rprimitive, is_int64_rprimitive, RStruct,
@@ -478,6 +478,15 @@ def visit_load_mem(self, op: LoadMem) -> None:
478478
type = self.ctype(op.type)
479479
self.emit_line('%s = *(%s *)%s;' % (dest, type, src))
480480

481+
def visit_set_mem(self, op: SetMem) -> None:
482+
dest = self.reg(op.dest)
483+
src = self.reg(op.src)
484+
type = self.ctype(op.type)
485+
# clang whines about self assignment (which we might generate
486+
# for some casts), so don't emit it.
487+
if dest != src:
488+
self.emit_line('*(%s *)%s = %s;' % (type, dest, src))
489+
481490
def visit_get_element_ptr(self, op: GetElementPtr) -> None:
482491
dest = self.reg(op)
483492
src = self.reg(op.src)

mypyc/ir/ops.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1414,6 +1414,55 @@ def accept(self, visitor: 'OpVisitor[T]') -> T:
14141414
return visitor.visit_load_mem(self)
14151415

14161416

1417+
class SetMem(Op):
1418+
"""Write a memory location.
1419+
1420+
*(type *)dest = src
1421+
1422+
Attributes:
1423+
type: Type of the read value
1424+
dest: Pointer to memory to write
1425+
src: Source value
1426+
base: If not None, the object from which we are reading memory.
1427+
It's used to avoid the target object from being freed via
1428+
reference counting. If the target is not in reference counted
1429+
memory, or we know that the target won't be freed, it can be
1430+
None.
1431+
"""
1432+
error_kind = ERR_NEVER
1433+
1434+
def __init__(self,
1435+
type: RType,
1436+
dest: Register,
1437+
src: Value,
1438+
base: Optional[Value],
1439+
line: int = -1) -> None:
1440+
super().__init__(line)
1441+
self.type = type
1442+
self.src = src
1443+
self.dest = dest
1444+
self.base = base
1445+
1446+
def sources(self) -> List[Value]:
1447+
if self.base:
1448+
return [self.src, self.base, self.dest]
1449+
else:
1450+
return [self.src, self.dest]
1451+
1452+
def stolen(self) -> List[Value]:
1453+
return [self.src]
1454+
1455+
def to_str(self, env: Environment) -> str:
1456+
if self.base:
1457+
base = env.format(', %r', self.base)
1458+
else:
1459+
base = ''
1460+
return env.format("%r = set_mem %r%s :: %r*", self.dest, self.src, base, self.type)
1461+
1462+
def accept(self, visitor: 'OpVisitor[T]') -> T:
1463+
return visitor.visit_set_mem(self)
1464+
1465+
14171466
class GetElementPtr(RegisterOp):
14181467
"""Get the address of a struct element"""
14191468
error_kind = ERR_NEVER
@@ -1569,6 +1618,10 @@ def visit_comparison_op(self, op: ComparisonOp) -> T:
15691618
def visit_load_mem(self, op: LoadMem) -> T:
15701619
raise NotImplementedError
15711620

1621+
@abstractmethod
1622+
def visit_set_mem(self, op: SetMem) -> T:
1623+
raise NotImplementedError
1624+
15721625
@abstractmethod
15731626
def visit_get_element_ptr(self, op: GetElementPtr) -> T:
15741627
raise NotImplementedError

mypyc/test/test_emitfunc.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
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, LoadAddress, ComparisonOp
13+
SetAttr, Op, Value, CallC, BinaryIntOp, LoadMem, GetElementPtr, LoadAddress, ComparisonOp,
14+
SetMem
1415
)
1516
from mypyc.ir.rtypes import (
1617
RTuple, RInstance, int_rprimitive, bool_rprimitive, list_rprimitive,
@@ -300,6 +301,10 @@ def test_load_mem(self) -> None:
300301
self.assert_emit(LoadMem(bool_rprimitive, self.ptr, self.s1),
301302
"""cpy_r_r00 = *(char *)cpy_r_ptr;""")
302303

304+
def test_set_mem(self) -> None:
305+
self.assert_emit(SetMem(bool_rprimitive, self.ptr, self.b, None),
306+
"""*(char *)cpy_r_ptr = cpy_r_b;""")
307+
303308
def test_get_element_ptr(self) -> None:
304309
r = RStruct("Foo", ["b", "i32", "i64"], [bool_rprimitive,
305310
int32_rprimitive, int64_rprimitive])

0 commit comments

Comments
 (0)