sim._pyrtl: translate ArrayProxy to pattern matching when supported.

Current the value compiler translates ArrayProxy into if-elif trees 
which can cause the compiler to crash due to deep recursion (#359).

After this commit, it instead translates them into pattern matching 
when it is supported (on Python >= 3.10) to avoid this problem.
This commit is contained in:
Jin Xue 2022-09-24 18:22:47 +08:00 committed by GitHub
parent c4be739d48
commit 3a51b61284
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1,6 +1,7 @@
import os import os
import tempfile import tempfile
from contextlib import contextmanager from contextlib import contextmanager
import sys
from ..hdl import * from ..hdl import *
from ..hdl.ast import SignalSet from ..hdl.ast import SignalSet
@ -10,6 +11,7 @@ from ._base import BaseProcess
__all__ = ["PyRTLProcess"] __all__ = ["PyRTLProcess"]
_USE_PATTERN_MATCHING = (sys.version_info >= (3, 10))
class PyRTLProcess(BaseProcess): class PyRTLProcess(BaseProcess):
__slots__ = ("is_comb", "runnable", "passive", "run") __slots__ = ("is_comb", "runnable", "passive", "run")
@ -228,16 +230,28 @@ class _RHSValueCompiler(_ValueCompiler):
gen_index = self.emitter.def_var("rhs_index", f"{index_mask:#x} & {self(value.index)}") gen_index = self.emitter.def_var("rhs_index", f"{index_mask:#x} & {self(value.index)}")
gen_value = self.emitter.gen_var("rhs_proxy") gen_value = self.emitter.gen_var("rhs_proxy")
if value.elems: if value.elems:
for index, elem in enumerate(value.elems): if _USE_PATTERN_MATCHING:
if index == 0: self.emitter.append(f"match {gen_index}:")
self.emitter.append(f"if {index} == {gen_index}:")
else:
self.emitter.append(f"elif {index} == {gen_index}:")
with self.emitter.indent(): with self.emitter.indent():
self.emitter.append(f"{gen_value} = {self(elem)}") for index, elem in enumerate(value.elems):
self.emitter.append(f"else:") self.emitter.append(f"case {index}:")
with self.emitter.indent(): with self.emitter.indent():
self.emitter.append(f"{gen_value} = {self(value.elems[-1])}") self.emitter.append(f"{gen_value} = {self(elem)}")
self.emitter.append("case _:")
with self.emitter.indent():
self.emitter.append(f"{gen_value} = {self(value.elems[-1])}")
else:
for index, elem in enumerate(value.elems):
if index == 0:
self.emitter.append(f"if {index} == {gen_index}:")
else:
self.emitter.append(f"elif {index} == {gen_index}:")
with self.emitter.indent():
self.emitter.append(f"{gen_value} = {self(elem)}")
self.emitter.append(f"else:")
with self.emitter.indent():
self.emitter.append(f"{gen_value} = {self(value.elems[-1])}")
return gen_value return gen_value
else: else:
return f"0" return f"0"
@ -319,16 +333,27 @@ class _LHSValueCompiler(_ValueCompiler):
index_mask = (1 << len(value.index)) - 1 index_mask = (1 << len(value.index)) - 1
gen_index = self.emitter.def_var("index", f"{self.rrhs(value.index)} & {index_mask:#x}") gen_index = self.emitter.def_var("index", f"{self.rrhs(value.index)} & {index_mask:#x}")
if value.elems: if value.elems:
for index, elem in enumerate(value.elems): if _USE_PATTERN_MATCHING:
if index == 0: self.emitter.append(f"match {gen_index}:")
self.emitter.append(f"if {index} == {gen_index}:")
else:
self.emitter.append(f"elif {index} == {gen_index}:")
with self.emitter.indent(): with self.emitter.indent():
self(elem)(arg) for index, elem in enumerate(value.elems):
self.emitter.append(f"else:") self.emitter.append(f"case {index}:")
with self.emitter.indent(): with self.emitter.indent():
self(value.elems[-1])(arg) self(elem)(arg)
self.emitter.append("case _:")
with self.emitter.indent():
self(value.elems[-1])(arg)
else:
for index, elem in enumerate(value.elems):
if index == 0:
self.emitter.append(f"if {index} == {gen_index}:")
else:
self.emitter.append(f"elif {index} == {gen_index}:")
with self.emitter.indent():
self(elem)(arg)
self.emitter.append(f"else:")
with self.emitter.indent():
self(value.elems[-1])(arg)
else: else:
self.emitter.append(f"pass") self.emitter.append(f"pass")
return gen return gen