mirror of https://github.com/llvm/circt.git
[PyCDE] Implement new DynamicInstance operation methodology (#2683)
This commit is contained in:
parent
61b2eda047
commit
050063d299
|
@ -17,7 +17,6 @@ class AppID:
|
|||
through hierarchy changes."""
|
||||
|
||||
def __init__(self, *appid: Tuple[str]):
|
||||
assert len(appid) > 0
|
||||
self._parts = list()
|
||||
for p in appid:
|
||||
assert isinstance(p, str)
|
||||
|
@ -25,6 +24,8 @@ class AppID:
|
|||
|
||||
@property
|
||||
def head(self) -> str:
|
||||
if len(self._parts) == 0:
|
||||
return ""
|
||||
return self._parts[0]
|
||||
|
||||
@property
|
||||
|
@ -40,7 +41,7 @@ class AppID:
|
|||
return AppID(*self._parts, part)
|
||||
|
||||
|
||||
class AppIDIndex(dict):
|
||||
class AppIDIndex(list):
|
||||
"""Model the AppID hierarchy. Provides the ability to attach attributes to
|
||||
AppIDs rather than instances, to get applied once the design is fully
|
||||
generated."""
|
||||
|
@ -57,7 +58,7 @@ class AppIDIndex(dict):
|
|||
return self._children[appid.head].lookup(appid.tail)
|
||||
|
||||
def add_attribute(self, attr: Tuple[str, ir.Attribute]) -> None:
|
||||
self[attr[0]] = attr[1]
|
||||
self.append(attr)
|
||||
|
||||
def find_unused(self) -> Union[AppIDIndex, Dict[str, AppIDIndex]]:
|
||||
if not self._used and len(self) > 0:
|
||||
|
@ -76,7 +77,7 @@ class AppIDIndex(dict):
|
|||
def _visit(idx, inst: Instance):
|
||||
attrs = idx.lookup(inst.appid)
|
||||
attrs._used = True
|
||||
for (akey, attr) in attrs.items():
|
||||
inst._attach_attribute(akey, attr)
|
||||
for attr in attrs:
|
||||
inst._attach_attribute(attr)
|
||||
|
||||
return lambda i, idx=self: _visit(idx, i)
|
||||
|
|
|
@ -19,5 +19,5 @@ def placement(subpath: Union[str, list[str]],
|
|||
num: int = 0):
|
||||
if isinstance(subpath, list):
|
||||
subpath = "|".join(subpath)
|
||||
loc = PhysLocation(devtype, x, y, num, subpath)
|
||||
return (f"loc:{subpath}", loc)
|
||||
loc = PhysLocation(devtype, x, y, num)
|
||||
return (subpath, loc)
|
||||
|
|
|
@ -7,7 +7,7 @@ import typing
|
|||
|
||||
from circt.dialects import msft
|
||||
|
||||
from mlir.ir import StringAttr, ArrayAttr, FlatSymbolRefAttr
|
||||
from mlir.ir import StringAttr, ArrayAttr, FlatSymbolRefAttr, Location
|
||||
|
||||
PrimitiveType = msft.PrimitiveType
|
||||
|
||||
|
@ -19,8 +19,7 @@ class PhysLocation:
|
|||
prim_type: typing.Union[str, PrimitiveType],
|
||||
x: int,
|
||||
y: int,
|
||||
num: typing.Union[int, None] = None,
|
||||
sub_path: str = ""):
|
||||
num: typing.Union[int, None] = None):
|
||||
|
||||
if isinstance(prim_type, str):
|
||||
prim_type = getattr(PrimitiveType, prim_type)
|
||||
|
@ -32,7 +31,7 @@ class PhysLocation:
|
|||
assert isinstance(x, int)
|
||||
assert isinstance(y, int)
|
||||
assert isinstance(num, int)
|
||||
self._loc = msft.PhysLocationAttr.get(prim_type, x, y, num, sub_path)
|
||||
self._loc = msft.PhysLocationAttr.get(prim_type, x, y, num)
|
||||
|
||||
def __str__(self) -> str:
|
||||
loc = self._loc
|
||||
|
@ -127,6 +126,10 @@ class PlacementDB:
|
|||
subpath = ""
|
||||
self._db.add_placement(loc._loc, path, subpath, entity._entity_extern)
|
||||
|
||||
def place(self, inst, loc: PhysLocation, subpath: str = ""):
|
||||
self._db.place(inst._dyn_inst.operation, loc._loc, subpath,
|
||||
Location.current)
|
||||
|
||||
|
||||
class EntityExtern:
|
||||
__slots__ = ["_entity_extern"]
|
||||
|
|
|
@ -5,162 +5,213 @@
|
|||
from __future__ import annotations
|
||||
from typing import Union
|
||||
|
||||
from pycde.devicedb import PhysLocation, PrimitiveDB, PlacementDB
|
||||
from numpy import isin
|
||||
|
||||
from .appid import AppID
|
||||
|
||||
from circt.dialects import hw, msft, seq
|
||||
from circt.dialects import hw, msft
|
||||
|
||||
import mlir.ir as ir
|
||||
import mlir.ir as _ir
|
||||
|
||||
|
||||
# TODO: bug: holds an Operation* without releasing it. Use a level of
|
||||
# indirection.
|
||||
class Instance:
|
||||
"""Represents a _specific_ instance, unique in a design. This is in contrast
|
||||
to a module instantiation within another module."""
|
||||
import pycde.system as system
|
||||
import pycde.module as module
|
||||
|
||||
__slots__ = ["parent", "_ref", "_root", "_child_cache", "_spec_mod"]
|
||||
|
||||
global_ref_counter = 0
|
||||
|
||||
def __init__(self,
|
||||
module: type,
|
||||
instOp: Union[msft.InstanceOp, seq.CompRegOp],
|
||||
parent: Instance,
|
||||
sys: system.System,
|
||||
primdb: PrimitiveDB = None):
|
||||
assert module is not None
|
||||
assert instOp is None or (isinstance(instOp, msft.InstanceOp) or
|
||||
isinstance(instOp, seq.CompRegOp))
|
||||
self.module = module
|
||||
self.instOp = instOp
|
||||
@staticmethod
|
||||
def _get(root: RootInstance,
|
||||
parent: Instance,
|
||||
spec_mod: module._SpecializedModule = None):
|
||||
self = Instance()
|
||||
self._root = root
|
||||
self.parent = parent
|
||||
if parent is None:
|
||||
self.placedb = PlacementDB(sys._get_circt_mod(module), primdb)
|
||||
assert isinstance(sys, Instance.system.System)
|
||||
self.sys = sys
|
||||
self._child_cache = None
|
||||
self._spec_mod = spec_mod
|
||||
return self
|
||||
|
||||
@property
|
||||
def path(self) -> list[Instance]:
|
||||
if self.parent is None:
|
||||
return []
|
||||
return self.parent.path + [self]
|
||||
|
||||
@property
|
||||
def root_module(self) -> hw.HWModuleOp:
|
||||
if self.parent is None:
|
||||
return self.module
|
||||
return self.parent.root_module
|
||||
|
||||
@property
|
||||
def root_instance(self) -> Instance:
|
||||
if self.parent is None:
|
||||
return self
|
||||
return self.parent.root_instance
|
||||
return self._root
|
||||
|
||||
@property
|
||||
def path_attr(self) -> ir.ArrayAttr:
|
||||
module_names = [self.sys._get_module_symbol(self.root_module)] + [
|
||||
self.sys._get_module_symbol(instance.module)
|
||||
for instance in self.path[:-1]
|
||||
]
|
||||
modules = [ir.StringAttr.get(name) for name in module_names]
|
||||
instances = [instance.name_attr for instance in self.path]
|
||||
def _dyn_inst(self) -> msft.DynamicInstanceOp:
|
||||
"""Return the raw CIRCT op backing this Instance.
|
||||
DANGEROUS! If used, take care to not hold on to the result object."""
|
||||
return self._root._create_or_get_dyn_inst(self)
|
||||
|
||||
@property
|
||||
def _module_symbol(self):
|
||||
assert self._spec_mod is not None
|
||||
return self._root._system._get_module_symbol(self._spec_mod)
|
||||
|
||||
def _path_attr(self) -> _ir.ArrayAttr:
|
||||
module_names = [self._root._module_symbol] + \
|
||||
[instance._module_symbol for instance in self.path[:-1]]
|
||||
modules = [_ir.StringAttr.get(name) for name in module_names]
|
||||
instances = [instance._name_attr for instance in self.path]
|
||||
inner_refs = [hw.InnerRefAttr.get(m, i) for m, i in zip(modules, instances)]
|
||||
return ir.ArrayAttr.get(inner_refs)
|
||||
return _ir.ArrayAttr.get(inner_refs)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.name_attr.value
|
||||
return str(self._name_attr).strip('"')
|
||||
|
||||
@property
|
||||
def name_attr(self):
|
||||
return ir.StringAttr(self.instOp.sym_name)
|
||||
|
||||
@property
|
||||
def is_root(self):
|
||||
return self.parent is None
|
||||
def _name_attr(self):
|
||||
return self._root._get_static_op(self).attributes["sym_name"]
|
||||
|
||||
@property
|
||||
def appid(self):
|
||||
return AppID(*[i.name for i in self.path])
|
||||
|
||||
@classmethod
|
||||
def get_global_ref_symbol(cls):
|
||||
counter = cls.global_ref_counter
|
||||
cls.global_ref_counter += 1
|
||||
return ir.StringAttr.get("ref" + str(counter))
|
||||
|
||||
def __repr__(self):
|
||||
path_names = map(lambda i: i.name, self.path)
|
||||
return "<instance: [" + ", ".join(path_names) + "]>"
|
||||
|
||||
def children(self):
|
||||
if self._child_cache is not None:
|
||||
return self._child_cache
|
||||
if self._spec_mod is None:
|
||||
return []
|
||||
symbols_in_mod = self._root._get_sym_ops_in_module(self._spec_mod)
|
||||
children = [self._root._create_instance(self, op) for op in symbols_in_mod]
|
||||
# TODO: make these weak refs
|
||||
self._child_cache = children
|
||||
return children
|
||||
|
||||
def walk(self, callback):
|
||||
"""Descend the instance hierarchy, calling back on each instance."""
|
||||
circt_mod = self.sys._get_circt_mod(self.module)
|
||||
if isinstance(circt_mod, msft.MSFTModuleExternOp):
|
||||
return
|
||||
for op in circt_mod.entry_block:
|
||||
if isinstance(op, seq.CompRegOp):
|
||||
inst = Instance(circt_mod, op, self, self.sys)
|
||||
callback(inst)
|
||||
continue
|
||||
callback(self)
|
||||
for child in self.children():
|
||||
child.walk(callback)
|
||||
|
||||
if not isinstance(op, msft.InstanceOp):
|
||||
continue
|
||||
def _attach_attribute(self, attr):
|
||||
import pycde.devicedb as devdb
|
||||
|
||||
assert "moduleName" in op.attributes
|
||||
tgt_modname = ir.FlatSymbolRefAttr(op.attributes["moduleName"]).value
|
||||
tgt_mod = self.sys._get_symbol_module(tgt_modname).modcls
|
||||
assert tgt_mod is not None
|
||||
inst = Instance(tgt_mod, op, self, self.sys)
|
||||
callback(inst)
|
||||
inst.walk(callback)
|
||||
|
||||
def _attach_attribute(self, sub_path: str, attr: ir.Attribute):
|
||||
if isinstance(attr, PhysLocation):
|
||||
attr = attr._loc
|
||||
|
||||
db = self.root_instance.placedb._db
|
||||
rc = db.add_placement(attr, self.path_attr, sub_path, self.instOp.operation)
|
||||
if not rc:
|
||||
raise ValueError("Failed to place")
|
||||
|
||||
# Create a global ref to this path.
|
||||
global_ref_symbol = Instance.get_global_ref_symbol()
|
||||
path_attr = self.path_attr
|
||||
with ir.InsertionPoint(self.sys.mod.body):
|
||||
global_ref = hw.GlobalRefOp(global_ref_symbol, path_attr)
|
||||
|
||||
# Attach the attribute to the global ref.
|
||||
global_ref.attributes["loc:" + sub_path] = attr
|
||||
|
||||
# Add references to the global ref for each instance through the hierarchy.
|
||||
for instance in self.path:
|
||||
# Find any existing global refs.
|
||||
if "circt.globalRef" in instance.instOp.attributes:
|
||||
global_refs = [
|
||||
ref for ref in ir.ArrayAttr(
|
||||
instance.instOp.attributes["circt.globalRef"])
|
||||
]
|
||||
else:
|
||||
global_refs = []
|
||||
|
||||
# Add the new global ref.
|
||||
global_refs.append(hw.GlobalRefAttr.get(global_ref_symbol))
|
||||
global_refs_attr = ir.ArrayAttr.get(global_refs)
|
||||
instance.instOp.attributes["circt.globalRef"] = global_refs_attr
|
||||
|
||||
# Set the expected inner_sym attribute on the instance to abide by the
|
||||
# global ref contract.
|
||||
instance.instOp.attributes["inner_sym"] = instance.name_attr
|
||||
assert isinstance(attr, tuple), "Only (subpath, loc) are supported"
|
||||
if isinstance(attr[1], devdb.PhysLocation):
|
||||
self._root._placedb.place(self, attr[1], attr[0])
|
||||
else:
|
||||
assert False
|
||||
|
||||
def place(self,
|
||||
subpath: Union[str, list[str]],
|
||||
devtype: msft.PrimitiveType,
|
||||
x: int,
|
||||
y: int,
|
||||
num: int = 0):
|
||||
num: int = 0,
|
||||
subpath: Union[str, list[str]] = ""):
|
||||
import pycde.devicedb as devdb
|
||||
if isinstance(subpath, list):
|
||||
subpath = "|".join(subpath)
|
||||
loc = msft.PhysLocationAttr.get(devtype, x, y, num, subpath)
|
||||
self._attach_attribute(subpath, loc)
|
||||
loc = devdb.PhysLocation(devtype, x, y, num)
|
||||
self._root.placedb.place(self, loc, subpath)
|
||||
|
||||
|
||||
class RootInstance(Instance):
|
||||
"""
|
||||
A root of an instance hierarchy starting at top-level 'module'.
|
||||
|
||||
Provides:
|
||||
- The placement database.
|
||||
- A (necessary) level of indirection into CIRCT IR.
|
||||
"""
|
||||
import pycde.system as system
|
||||
import pycde.devicedb as devdb
|
||||
from .module import _SpecializedModule
|
||||
|
||||
__slots__ = [
|
||||
"_module", "_placedb", "_subsymbol_cache", "_inst_to_static_op_cache",
|
||||
"_inst_to_dyn_op_cache", "_system"
|
||||
]
|
||||
|
||||
# TODO: Support rebuilding the caches.
|
||||
|
||||
@staticmethod
|
||||
def _get(module: _SpecializedModule, sys: system.System):
|
||||
self = RootInstance()
|
||||
self._spec_mod = module
|
||||
self._system = sys
|
||||
self._placedb = None
|
||||
self._root = self
|
||||
self._subsymbol_cache = {}
|
||||
self._inst_to_static_op_cache = {self: sys._get_circt_mod(module)}
|
||||
self._inst_to_dyn_op_cache = {}
|
||||
self._child_cache = None
|
||||
return self
|
||||
|
||||
def _clear_cache(self):
|
||||
"""Clear out all of the Operation* references."""
|
||||
self._subsymbol_cache = None
|
||||
self._inst_to_static_op_cache = None
|
||||
self._inst_to_dyn_op_cache = None
|
||||
self._child_cache = None
|
||||
|
||||
def createdb(self, primdb: devdb.PrimitiveDB = None):
|
||||
import pycde.devicedb as devdb
|
||||
self._placedb = devdb.PlacementDB(
|
||||
self._system._get_circt_mod(self._spec_mod), primdb)
|
||||
|
||||
def _get_static_op(self, inst: Instance):
|
||||
# We don't support cache rebuilds yet.
|
||||
assert self._inst_to_static_op_cache is not None
|
||||
assert inst in self._inst_to_static_op_cache
|
||||
return self._inst_to_static_op_cache[inst]
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return "<<root>>"
|
||||
|
||||
@property
|
||||
def _name_attr(self):
|
||||
return None
|
||||
|
||||
@property
|
||||
def placedb(self):
|
||||
if self._placedb is None:
|
||||
raise Exception("Must `createdb` first")
|
||||
return self._placedb
|
||||
|
||||
@property
|
||||
def path(self) -> list[Instance]:
|
||||
return []
|
||||
|
||||
def _create_or_get_dyn_inst(self, inst: Instance):
|
||||
# We don't support cache rebuilding yet
|
||||
assert self._inst_to_dyn_op_cache is not None
|
||||
if inst not in self._inst_to_dyn_op_cache:
|
||||
with self._system._get_ip():
|
||||
self._inst_to_dyn_op_cache[inst] = \
|
||||
msft.DynamicInstanceOp.create(inst._path_attr())
|
||||
return self._inst_to_dyn_op_cache[inst]
|
||||
|
||||
def _create_instance(self, parent: Instance, static_op: _ir.Operation):
|
||||
import circt.dialects.msft as circtms
|
||||
spec_mod = None
|
||||
if isinstance(static_op, circtms.InstanceOp):
|
||||
spec_mod = self._system._get_symbol_module(static_op.moduleName)
|
||||
inst = Instance._get(self, parent, spec_mod)
|
||||
self._inst_to_static_op_cache[inst] = static_op
|
||||
return inst
|
||||
|
||||
def _get_sym_ops_in_module(self, instance_module: _SpecializedModule):
|
||||
if instance_module not in self._subsymbol_cache:
|
||||
circt_mod = self._system._get_circt_mod(instance_module)
|
||||
if isinstance(circt_mod, msft.MSFTModuleExternOp):
|
||||
return []
|
||||
|
||||
def has_symbol(op):
|
||||
return "sym_name" in op.attributes
|
||||
|
||||
self._subsymbol_cache[instance_module] = \
|
||||
[op for op in circt_mod.entry_block if has_symbol(op)]
|
||||
|
||||
return self._subsymbol_cache[instance_module]
|
||||
|
|
|
@ -6,7 +6,7 @@ from pycde.devicedb import EntityExtern, PrimitiveDB, PhysicalRegion
|
|||
|
||||
from .module import _SpecializedModule
|
||||
from .pycde_types import types
|
||||
from .instance import Instance
|
||||
from .instance import Instance, RootInstance
|
||||
|
||||
import mlir
|
||||
import mlir.ir as ir
|
||||
|
@ -35,12 +35,12 @@ class System:
|
|||
|
||||
__slots__ = [
|
||||
"mod", "modules", "name", "passed", "_module_symbols", "_symbol_modules",
|
||||
"_old_system_token", "_symbols", "_generate_queue", "_primdb",
|
||||
"_output_directory", "files"
|
||||
"_old_system_token", "_symbols", "_generate_queue", "_output_directory",
|
||||
"files", "_instance_cache"
|
||||
]
|
||||
|
||||
PASSES = """
|
||||
msft-partition,
|
||||
msft-lower-instances, msft-partition,
|
||||
lower-msft-to-hw{{verilog-file={verilog_file}}},
|
||||
lower-seq-to-sv, hw.module(prettify-verilog), hw.module(hw-cleanup),
|
||||
msft-export-tcl{{tops={tops} tcl-file={tcl_file}}}
|
||||
|
@ -48,7 +48,6 @@ class System:
|
|||
|
||||
def __init__(self,
|
||||
modules,
|
||||
primdb: PrimitiveDB = None,
|
||||
name: str = "PyCDESystem",
|
||||
output_directory: str = None):
|
||||
self.passed = False
|
||||
|
@ -59,10 +58,9 @@ class System:
|
|||
self._symbol_modules: dict[str, _SpecializedModule] = {}
|
||||
self._symbols: typing.Set[str] = None
|
||||
self._generate_queue = []
|
||||
self._instance_cache: dict[_SpecializedModule, RootInstance] = {}
|
||||
self.files: typing.Set[str] = set()
|
||||
|
||||
self._primdb = primdb
|
||||
|
||||
if output_directory is None:
|
||||
output_directory = os.path.join(os.getcwd(), self.name)
|
||||
self._output_directory = output_directory
|
||||
|
@ -73,6 +71,10 @@ class System:
|
|||
def _get_ip(self):
|
||||
return ir.InsertionPoint(self.mod.body)
|
||||
|
||||
@staticmethod
|
||||
def set_debug():
|
||||
ir._GlobalDebug.flag = True
|
||||
|
||||
# TODO: Return a read-only proxy.
|
||||
@property
|
||||
def symbols(self) -> typing.Dict[str, ir.Operation]:
|
||||
|
@ -129,6 +131,8 @@ class System:
|
|||
|
||||
def _get_symbol_module(self, symbol):
|
||||
"""Get the _SpecializedModule for a symbol."""
|
||||
if isinstance(symbol, ir.FlatSymbolRefAttr):
|
||||
symbol = symbol.value
|
||||
return self._symbol_modules[symbol]
|
||||
|
||||
def _get_module_symbol(self, spec_mod):
|
||||
|
@ -201,7 +205,10 @@ class System:
|
|||
return len(self._generate_queue)
|
||||
|
||||
def get_instance(self, mod_cls: object) -> Instance:
|
||||
return Instance(mod_cls, None, None, self, self._primdb)
|
||||
mod = mod_cls._pycde_mod
|
||||
if mod not in self._instance_cache:
|
||||
self._instance_cache[mod] = RootInstance._get(mod, self)
|
||||
return self._instance_cache[mod]
|
||||
|
||||
class DevNull:
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ class Value:
|
|||
clk=clk,
|
||||
reset=rst,
|
||||
name=name,
|
||||
inner_sym=name)
|
||||
sym_name=name)
|
||||
|
||||
@property
|
||||
def _namehint_attrname(self):
|
||||
|
|
|
@ -26,7 +26,7 @@ class CompReg:
|
|||
clk=ports.clk,
|
||||
input=ports.input,
|
||||
name="reg",
|
||||
inner_sym="reg")
|
||||
sym_name="reg")
|
||||
ports.output = compreg
|
||||
|
||||
|
||||
|
@ -37,7 +37,9 @@ appid.lookup(pycde.AppID("reg")).add_attribute(loc)
|
|||
mod = pycde.System([CompReg], name="CompReg", output_directory=sys.argv[1])
|
||||
mod.print()
|
||||
mod.generate()
|
||||
mod.get_instance(CompReg).walk(appid.apply_attributes_visitor)
|
||||
top_inst = mod.get_instance(CompReg)
|
||||
top_inst.createdb()
|
||||
top_inst.walk(appid.apply_attributes_visitor)
|
||||
mod.print()
|
||||
mod.emit_outputs()
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ class UnParameterized:
|
|||
|
||||
@pycde.generator
|
||||
def construct(mod):
|
||||
Nothing()
|
||||
Nothing().name = "nothing_inst"
|
||||
mod.y = mod.x
|
||||
|
||||
|
||||
|
@ -35,8 +35,8 @@ class Test:
|
|||
@pycde.generator
|
||||
def build(_):
|
||||
c1 = pycde.dialects.hw.ConstantOp(pycde.types.i1, 1)
|
||||
UnParameterized(x=c1)
|
||||
UnParameterized(x=c1)
|
||||
UnParameterized(x=c1).name = "unparam"
|
||||
UnParameterized(x=c1).name = "unparam"
|
||||
|
||||
|
||||
# Set up the primitive locations. Errors out if location is placed but doesn't
|
||||
|
@ -54,7 +54,7 @@ print(PhysLocation(PrimitiveType.DSP, 39, 25))
|
|||
|
||||
# CHECK: msft.module @UnParameterized
|
||||
# CHECK-NOT: msft.module @UnParameterized
|
||||
t = pycde.System([Test], primdb, name="Test", output_directory=sys.argv[1])
|
||||
t = pycde.System([Test], name="Test", output_directory=sys.argv[1])
|
||||
t.generate(["construct"])
|
||||
t.print()
|
||||
|
||||
|
@ -63,68 +63,67 @@ UnParameterized.print()
|
|||
|
||||
# CHECK-LABEL: === Hierarchy
|
||||
print("=== Hierarchy")
|
||||
# CHECK-NEXT: <instance: []>
|
||||
# CHECK-NEXT: <instance: [UnParameterized]>
|
||||
# CHECK-NEXT: <instance: [UnParameterized, Nothing]>
|
||||
# CHECK-NEXT: <instance: [UnParameterized_1]>
|
||||
# CHECK-NEXT: <instance: [UnParameterized_1, Nothing]>
|
||||
mod = t.get_instance(Test).walk(lambda inst: print(inst))
|
||||
|
||||
locs = pycde.AppIDIndex()
|
||||
locs.lookup(pycde.AppID("UnParameterized_1"))["loc"] = \
|
||||
(["memory", "bank"], PrimitiveType.M20K, 39, 25, 0)
|
||||
test_inst = t.get_instance(Test)
|
||||
test_inst.createdb(primdb)
|
||||
mod = test_inst.walk(lambda inst: print(inst))
|
||||
|
||||
|
||||
def place_inst(inst):
|
||||
global x, y
|
||||
if inst.module == Nothing:
|
||||
inst.place("dsp_inst", PrimitiveType.DSP, x, y)
|
||||
x += 1
|
||||
y += 2
|
||||
else:
|
||||
props = locs.lookup(inst.appid)
|
||||
if "loc" in props:
|
||||
inst.place(*props["loc"])
|
||||
if inst.name == "UnParameterized_1":
|
||||
inst.place(PrimitiveType.M20K, 39, 25, 0, "memory|bank")
|
||||
|
||||
|
||||
x = 0
|
||||
y = 10
|
||||
t.get_instance(Test).walk(place_inst)
|
||||
|
||||
instance_attrs = pycde.AppIDIndex()
|
||||
loc = placement(["memory", "bank"], PrimitiveType.M20K, 15, 25, 0)
|
||||
instance_attrs.lookup(pycde.AppID("UnParameterized")).add_attribute(loc)
|
||||
loc = placement(["memory", "bank"], PrimitiveType.DSP, 39, 25, 0)
|
||||
loc = placement("", PrimitiveType.DSP, 39, 25, 0)
|
||||
instance_attrs.lookup(pycde.AppID("UnParameterized",
|
||||
"Nothing")).add_attribute(loc)
|
||||
|
||||
region1 = t.create_physical_region("region_0").add_bounds((0, 10), (0, 10))
|
||||
region1.add_bounds((10, 20), (10, 20))
|
||||
ref = region1.get_ref()
|
||||
instance_attrs.lookup(pycde.AppID("UnParameterized",
|
||||
"Nothing")).add_attribute(ref)
|
||||
# TODO: Add back physical region support
|
||||
|
||||
region_anon = t.create_physical_region()
|
||||
assert region_anon._physical_region.sym_name.value == "region_1"
|
||||
# region1 = t.create_physical_region("region_0").add_bounds((0, 10), (0, 10))
|
||||
# region1.add_bounds((10, 20), (10, 20))
|
||||
# ref = region1.get_ref()
|
||||
# instance_attrs.lookup(pycde.AppID("UnParameterized",
|
||||
# "Nothing")).add_attribute(ref)
|
||||
|
||||
region_explicit = t.create_physical_region("region_1")
|
||||
assert region_explicit._physical_region.sym_name.value == "region_1_1"
|
||||
# region_anon = t.create_physical_region()
|
||||
# assert region_anon._physical_region.sym_name.value == "region_1"
|
||||
|
||||
# region_explicit = t.create_physical_region("region_1")
|
||||
# assert region_explicit._physical_region.sym_name.value == "region_1_1"
|
||||
|
||||
test_inst = t.get_instance(Test)
|
||||
test_inst.createdb()
|
||||
test_inst.walk(instance_attrs.apply_attributes_visitor)
|
||||
|
||||
reserved_loc = PhysLocation(PrimitiveType.M20K, 40, 40, 0)
|
||||
entity_extern = t.create_entity_extern("tag")
|
||||
test_inst.placedb.reserve_location(reserved_loc, entity_extern)
|
||||
# TODO: add back anonymous reservations
|
||||
|
||||
# reserved_loc = PhysLocation(PrimitiveType.M20K, 40, 40, 0)
|
||||
# entity_extern = t.create_entity_extern("tag")
|
||||
# test_inst.placedb.reserve_location(reserved_loc, entity_extern)
|
||||
|
||||
assert test_inst.placedb.get_instance_at(loc[1]) is not None
|
||||
assert test_inst.placedb.get_instance_at(
|
||||
PhysLocation(PrimitiveType.M20K, 0, 0, 0)) is None
|
||||
assert test_inst.placedb.get_instance_at(reserved_loc) is not None
|
||||
# assert test_inst.placedb.get_instance_at(reserved_loc) is not None
|
||||
|
||||
assert instance_attrs.find_unused() is None
|
||||
instance_attrs.lookup(pycde.AppID("doesnotexist")).add_attribute(loc)
|
||||
assert (len(instance_attrs.find_unused()) == 1)
|
||||
|
||||
print("=== Pre-pass mlir dump")
|
||||
t.print()
|
||||
|
||||
print("=== Running passes")
|
||||
t.run_passes()
|
||||
|
||||
print("=== Final mlir dump")
|
||||
|
@ -132,13 +131,9 @@ t.print()
|
|||
|
||||
# OUTPUT-LABEL: proc Test_config { parent }
|
||||
# OUTPUT-NOT: set_location_assignment M20K_X40_Y40
|
||||
# OUTPUT-DAG: set_location_assignment MPDSP_X0_Y10_N0 -to $parent|UnParameterized|Nothing|dsp_inst
|
||||
# OUTPUT-DAG: set_location_assignment MPDSP_X39_Y25_N0 -to $parent|UnParameterized|Nothing|memory|bank
|
||||
# OUTPUT-DAG: set_location_assignment M20K_X15_Y25_N0 -to $parent|UnParameterized|memory|bank
|
||||
# OUTPUT-DAG: set_location_assignment MPDSP_X1_Y12_N0 -to $parent|UnParameterized_1|Nothing|dsp_inst
|
||||
# OUTPUT-DAG: set_location_assignment M20K_X39_Y25_N0 -to $parent|UnParameterized_1|memory|bank
|
||||
# OUTPUT-DAG: set_instance_assignment -name PLACE_REGION "X0 Y0 X10 Y10;X10 Y10 X20 Y20" -to $parent|UnParameterized|Nothing
|
||||
# OUTPUT-DAG: set_instance_assignment -name RESERVE_PLACE_REGION OFF -to $parent|UnParameterized|Nothing
|
||||
# OUTPUT-DAG: set_instance_assignment -name CORE_ONLY_PLACE_REGION ON -to $parent|UnParameterized|Nothing
|
||||
# OUTPUT-DAG: set_instance_assignment -name REGION_NAME region_0 -to $parent|UnParameterized|Nothing
|
||||
# OUTPUT-DAG: set_location_assignment M20K_X15_Y25_N0 -to $parent|UnParameterized|memory|bank
|
||||
# OUTPUT-DAG: set_location_assignment MPDSP_X39_Y25_N0 -to $parent|UnParameterized|Nothing
|
||||
# OUTPUT-NOT: set_location_assignment
|
||||
# OUTPUT-NEXT: }
|
||||
t.emit_outputs()
|
||||
|
|
|
@ -33,9 +33,8 @@ typedef int32_t CirctMSFTPrimitiveType;
|
|||
|
||||
MLIR_CAPI_EXPORTED bool
|
||||
circtMSFTAttributeIsAPhysLocationAttribute(MlirAttribute);
|
||||
MLIR_CAPI_EXPORTED MlirAttribute
|
||||
circtMSFTPhysLocationAttrGet(MlirContext, CirctMSFTPrimitiveType, uint64_t x,
|
||||
uint64_t y, uint64_t num, MlirStringRef subPath);
|
||||
MLIR_CAPI_EXPORTED MlirAttribute circtMSFTPhysLocationAttrGet(
|
||||
MlirContext, CirctMSFTPrimitiveType, uint64_t x, uint64_t y, uint64_t num);
|
||||
MLIR_CAPI_EXPORTED CirctMSFTPrimitiveType
|
||||
circtMSFTPhysLocationAttrGetPrimitiveType(MlirAttribute);
|
||||
MLIR_CAPI_EXPORTED uint64_t circtMSFTPhysLocationAttrGetX(MlirAttribute);
|
||||
|
|
|
@ -143,14 +143,13 @@ void circt::python::populateDialectMSFTSubmodule(py::module &m) {
|
|||
.def_classmethod(
|
||||
"get",
|
||||
[](py::object cls, PrimitiveType devType, uint64_t x, uint64_t y,
|
||||
uint64_t num, std::string subPath, MlirContext ctxt) {
|
||||
auto cSubPath = mlirStringRefCreateFromCString(subPath.c_str());
|
||||
uint64_t num, MlirContext ctxt) {
|
||||
return cls(circtMSFTPhysLocationAttrGet(ctxt, (uint64_t)devType, x,
|
||||
y, num, cSubPath));
|
||||
y, num));
|
||||
},
|
||||
"Create a physical location attribute", py::arg(),
|
||||
py::arg("dev_type"), py::arg("x"), py::arg("y"), py::arg("num"),
|
||||
py::arg("sub_path") = py::str(""), py::arg("ctxt") = py::none())
|
||||
py::arg("ctxt") = py::none())
|
||||
.def_property_readonly(
|
||||
"devtype",
|
||||
[](MlirAttribute self) {
|
||||
|
|
|
@ -139,6 +139,13 @@ class PhysicalRegionOp:
|
|||
self.attributes["bounds"] = new_bounds
|
||||
|
||||
|
||||
class InstanceOp:
|
||||
|
||||
@property
|
||||
def moduleName(self):
|
||||
return _ir.FlatSymbolRefAttr(self.attributes["moduleName"])
|
||||
|
||||
|
||||
class EntityExternOp:
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -150,8 +150,8 @@ bool circtMSFTAttributeIsAPhysLocationAttribute(MlirAttribute attr) {
|
|||
}
|
||||
MlirAttribute circtMSFTPhysLocationAttrGet(MlirContext cCtxt,
|
||||
CirctMSFTPrimitiveType devType,
|
||||
uint64_t x, uint64_t y, uint64_t num,
|
||||
MlirStringRef subPath) {
|
||||
uint64_t x, uint64_t y,
|
||||
uint64_t num) {
|
||||
auto *ctxt = unwrap(cCtxt);
|
||||
return wrap(PhysLocationAttr::get(
|
||||
ctxt, PrimitiveTypeAttr::get(ctxt, (PrimitiveType)devType), x, y, num));
|
||||
|
|
|
@ -158,7 +158,8 @@ LogicalResult DynamicInstanceOpLowering::matchAndRewrite(
|
|||
}
|
||||
}
|
||||
if (symNotFound)
|
||||
return failure();
|
||||
return rewriter.notifyMatchFailure(
|
||||
inst, "Could not find operation corresponding to appid");
|
||||
|
||||
// Relocate all my children.
|
||||
rewriter.setInsertionPointAfter(inst);
|
||||
|
@ -633,13 +634,10 @@ void PassCommon::getAndSortModules(ModuleOp topMod,
|
|||
|
||||
/// Fill a symbol cache with all the top level symbols.
|
||||
void PassCommon::populateSymbolCache(mlir::ModuleOp mod) {
|
||||
for (Operation &op : mod.getBody()->getOperations()) {
|
||||
StringAttr symName = SymbolTable::getSymbolName(&op);
|
||||
if (!symName)
|
||||
continue;
|
||||
// Add the symbol to the cache.
|
||||
topLevelSyms.addDefinition(symName, &op);
|
||||
}
|
||||
for (Operation &op : mod.getBody()->getOperations())
|
||||
if (auto symOp = dyn_cast<mlir::SymbolOpInterface>(op))
|
||||
if (auto name = symOp.getNameAttr())
|
||||
topLevelSyms.addDefinition(name, symOp);
|
||||
topLevelSyms.freeze();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue