Skip to content

Commit ec6d9d9

Browse files
authored
[mypyc] Fix ircheck if register is initialized through LoadAddress (#13944)
It's okay to take an address of a register, pass it to a function that initializes the register, and then read the register. Ircheck complained about an invalid op reference to register in this case. It affected at least async code.
1 parent 8ef701d commit ec6d9d9

File tree

2 files changed

+35
-4
lines changed

2 files changed

+35
-4
lines changed

mypyc/analysis/ircheck.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,11 @@ def check_op_sources_valid(fn: FuncIR) -> list[FnError]:
129129
for block in fn.blocks:
130130
valid_ops.update(block.ops)
131131

132-
valid_registers.update([op.dest for op in block.ops if isinstance(op, BaseAssign)])
132+
for op in block.ops:
133+
if isinstance(op, BaseAssign):
134+
valid_registers.add(op.dest)
135+
elif isinstance(op, LoadAddress) and isinstance(op.src, Register):
136+
valid_registers.add(op.src)
133137

134138
valid_registers.update(fn.arg_regs)
135139

@@ -150,7 +154,7 @@ def check_op_sources_valid(fn: FuncIR) -> list[FnError]:
150154
if source not in valid_registers:
151155
errors.append(
152156
FnError(
153-
source=op, desc=f"Invalid op reference to register {source.name}"
157+
source=op, desc=f"Invalid op reference to register {source.name!r}"
154158
)
155159
)
156160

mypyc/test/test_ircheck.py

+29-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,17 @@
55
from mypyc.analysis.ircheck import FnError, can_coerce_to, check_func_ir
66
from mypyc.ir.class_ir import ClassIR
77
from mypyc.ir.func_ir import FuncDecl, FuncIR, FuncSignature
8-
from mypyc.ir.ops import Assign, BasicBlock, Goto, Integer, LoadLiteral, Op, Register, Return
8+
from mypyc.ir.ops import (
9+
Assign,
10+
BasicBlock,
11+
Goto,
12+
Integer,
13+
LoadAddress,
14+
LoadLiteral,
15+
Op,
16+
Register,
17+
Return,
18+
)
919
from mypyc.ir.pprint import format_func
1020
from mypyc.ir.rtypes import (
1121
RInstance,
@@ -16,6 +26,7 @@
1626
int64_rprimitive,
1727
none_rprimitive,
1828
object_rprimitive,
29+
pointer_rprimitive,
1930
str_rprimitive,
2031
)
2132

@@ -88,7 +99,7 @@ def test_invalid_register_source(self) -> None:
8899
ret = Return(value=Register(type=none_rprimitive, name="r1"))
89100
block = self.basic_block([ret])
90101
fn = FuncIR(decl=self.func_decl(name="func_1"), arg_regs=[], blocks=[block])
91-
assert_has_error(fn, FnError(source=ret, desc="Invalid op reference to register r1"))
102+
assert_has_error(fn, FnError(source=ret, desc="Invalid op reference to register 'r1'"))
92103

93104
def test_invalid_op_source(self) -> None:
94105
ret = Return(value=LoadLiteral(value="foo", rtype=str_rprimitive))
@@ -170,3 +181,19 @@ def test_pprint(self) -> None:
170181
" goto L1",
171182
" ERR: Invalid control operation target: 1",
172183
]
184+
185+
def test_load_address_declares_register(self) -> None:
186+
rx = Register(str_rprimitive, "x")
187+
ry = Register(pointer_rprimitive, "y")
188+
load_addr = LoadAddress(pointer_rprimitive, rx)
189+
assert_no_errors(
190+
FuncIR(
191+
decl=self.func_decl(name="func_1"),
192+
arg_regs=[],
193+
blocks=[
194+
self.basic_block(
195+
ops=[load_addr, Assign(ry, load_addr), Return(value=NONE_VALUE)]
196+
)
197+
],
198+
)
199+
)

0 commit comments

Comments
 (0)