Skip to content

Commit 09029cd

Browse files
committed
hdl._ir: remember origins of a fragment during elaboration.
This isn't expected to result in a significant increase in memory use, so for now it's enabled by default. Elaboration chains where it is not desired to preserve origins can delete the `origins` attribute from the fragment and nothing will be stored. The interface `Fragment.origins` remains private, as is the rest of the `Fragment` interface (including itself), but it enables certain codebases that currently use a much more invasive technique to rely on reading a single private field.
1 parent c40cfc9 commit 09029cd

File tree

2 files changed

+32
-0
lines changed

2 files changed

+32
-0
lines changed

amaranth/hdl/_ir.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,11 @@ class Fragment:
3131
@staticmethod
3232
def get(obj, platform):
3333
code = None
34+
origins = []
3435
while True:
3536
if isinstance(obj, Fragment):
37+
if hasattr(obj, "origins"):
38+
obj.origins = tuple(origins)
3639
return obj
3740
elif isinstance(obj, Elaboratable):
3841
code = obj.elaborate.__code__
@@ -58,6 +61,7 @@ def get(obj, platform):
5861
category=UserWarning,
5962
filename=code.co_filename,
6063
lineno=code.co_firstlineno)
64+
origins.append(obj)
6165
obj = new_obj
6266

6367
def __init__(self, *, src_loc=None):
@@ -70,6 +74,7 @@ def __init__(self, *, src_loc=None):
7074
self.generated = OrderedDict()
7175
self.flatten = False
7276
self.src_loc = src_loc
77+
self.origins = None
7378

7479
def add_ports(self, *ports, dir):
7580
assert dir in ("i", "o", "io")

tests/test_hdl_ir.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from amaranth.hdl._ast import *
66
from amaranth.hdl._cd import *
7+
from amaranth.hdl._dsl import *
78
from amaranth.hdl._ir import *
89
from amaranth.hdl._mem import *
910

@@ -919,3 +920,29 @@ def test_assign_names_to_fragments_collide_with_signal(self):
919920
f: ("top",),
920921
a_f: ("top", "a$U$0")
921922
})
923+
924+
925+
class ElaboratesTo(Elaboratable):
926+
def __init__(self, lower):
927+
self.lower = lower
928+
929+
def elaborate(self, platform):
930+
return self.lower
931+
932+
933+
class OriginsTestCase(FHDLTestCase):
934+
def test_origins(self):
935+
elab1 = ElaboratesTo(elab2 := ElaboratesTo(m := Module()))
936+
frag = Fragment.get(elab1, platform=None)
937+
self.assertEqual(len(frag.origins), 3)
938+
self.assertIsInstance(frag.origins, tuple)
939+
self.assertIs(frag.origins[0], elab1)
940+
self.assertIs(frag.origins[1], elab2)
941+
self.assertIs(frag.origins[2], m)
942+
943+
def test_origins_disable(self):
944+
inst = Instance("test")
945+
del inst.origins
946+
elab = ElaboratesTo(inst)
947+
frag = Fragment.get(elab, platform=None)
948+
self.assertFalse(hasattr(frag, "_origins"))

0 commit comments

Comments
 (0)