mirror of https://github.com/llvm/circt.git
[MSFT] Update termination conditions when partitioning refs. (#2450)
The previous conditions to trigger a global ref update were only valid for simple circuits where each instance is instantiated once. Furthermore, the way global refs bubble up is also updated to use each global ref locally in order to handle multiple instantiations.
This commit is contained in:
parent
1f0bf86298
commit
d6a959d91e
|
@ -591,35 +591,45 @@ void PartitionPass::bubbleUpGlobalRefs(Operation *op) {
|
|||
if (!globalRefs)
|
||||
return;
|
||||
|
||||
// GlobalRefs use the inner_sym attribute, so keep it up to date.
|
||||
op->setAttr("inner_sym", StringAttr::get(op->getContext(), ::getOpName(op)));
|
||||
|
||||
for (auto globalRef : globalRefs.getAsRange<hw::GlobalRefAttr>()) {
|
||||
// Resolve the GlobalRefOp and get its path.
|
||||
auto refSymbol = globalRef.getGlblSym();
|
||||
auto globalRefOp = dyn_cast_or_null<hw::GlobalRefOp>(
|
||||
topLevelSyms.getDefinition(refSymbol));
|
||||
assert(globalRefOp && "symbol must reference a GlobalRefOp");
|
||||
auto oldPath = globalRefOp.namepath().getAsRange<hw::InnerRefAttr>();
|
||||
auto oldPath = globalRefOp.namepath().getValue();
|
||||
assert(!oldPath.empty());
|
||||
|
||||
// If the path already points to the target design partition, we are done.
|
||||
auto leafModule = oldPath.back().cast<hw::InnerRefAttr>().getModule();
|
||||
auto partAttr = op->getAttrOfType<SymbolRefAttr>("targetDesignPartition");
|
||||
if (partAttr.getRootReference() == leafModule)
|
||||
return;
|
||||
assert(oldPath.size() > 1);
|
||||
|
||||
// Construct a new path starting from the old path.
|
||||
SmallVector<Attribute> newPath(oldPath);
|
||||
SmallVector<Attribute> newPath(oldPath.begin(), oldPath.end());
|
||||
|
||||
// If there aren't two elements in the path, this GlobalRefOp has already
|
||||
// been updated.
|
||||
if (newPath.size() < 2)
|
||||
return;
|
||||
|
||||
// Splice the last two elements in the path, using the combined name from
|
||||
// the op's attributes, and taking the module from the second to last
|
||||
// element.
|
||||
newPath.pop_back_val().cast<hw::InnerRefAttr>();
|
||||
// Use the elements in the path to construct a name that matches the format
|
||||
// going into inner_ref above. Splice the last two elements in the path,
|
||||
// bulding the name from the two elements' names, and taking the module from
|
||||
// the second to last element. Note that we use the global ref directly so
|
||||
// we can update all paths to an instance the first time it is visited. This
|
||||
// saves on bookkeeping to match up the new inner_ref to the global refs.
|
||||
// TODO: consider adding state to simplify this.
|
||||
auto lastElement = newPath.pop_back_val().cast<hw::InnerRefAttr>();
|
||||
auto nextElement = newPath.pop_back_val().cast<hw::InnerRefAttr>();
|
||||
auto newModule = nextElement.getModule();
|
||||
auto newNameAttr = StringAttr::get(op->getContext(), ::getOpName(op));
|
||||
auto lastName = lastElement.getName().getValue();
|
||||
auto nextName = nextElement.getName().getValue();
|
||||
auto newNameAttr =
|
||||
StringAttr::get(op->getContext(), nextName + "." + lastName);
|
||||
auto newLeaf = hw::InnerRefAttr::get(newModule, newNameAttr);
|
||||
newPath.push_back(newLeaf);
|
||||
|
||||
// GlobalRefs use the inner_sym attribute, so keep it up to date.
|
||||
op->setAttr("inner_sym", newNameAttr);
|
||||
|
||||
// Update the path on the GlobalRefOp.
|
||||
auto newPathAttr = ArrayAttr::get(op->getContext(), newPath);
|
||||
globalRefOp.namepathAttr(newPathAttr);
|
||||
|
@ -639,7 +649,8 @@ void PartitionPass::pushDownGlobalRefs(Operation *op, DesignPartitionOp partOp,
|
|||
auto globalRefOp = dyn_cast_or_null<hw::GlobalRefOp>(
|
||||
topLevelSyms.getDefinition(refSymbol));
|
||||
assert(globalRefOp && "symbol must reference a GlobalRefOp");
|
||||
auto oldPath = globalRefOp.namepath().getAsRange<hw::InnerRefAttr>();
|
||||
auto oldPath = globalRefOp.namepath().getValue();
|
||||
assert(!oldPath.empty());
|
||||
|
||||
// Get the module containing the partition and the partition's name.
|
||||
auto partAttr = op->getAttrOfType<SymbolRefAttr>("targetDesignPartition");
|
||||
|
@ -648,15 +659,20 @@ void PartitionPass::pushDownGlobalRefs(Operation *op, DesignPartitionOp partOp,
|
|||
auto partModName = partOp.verilogNameAttr();
|
||||
assert(partModName);
|
||||
|
||||
// Construct a new path starting from the old path.
|
||||
SmallVector<Attribute> newPath(oldPath);
|
||||
auto lastElement = newPath.pop_back_val().cast<hw::InnerRefAttr>();
|
||||
|
||||
// If the last element in the path is not pointing at the module
|
||||
// containing the partition, this GlobalRefOp has already been updated.
|
||||
if (lastElement.getModule() != partMod)
|
||||
// All nodes along the path point up to the global ref. Only proceed if we
|
||||
// are at the leaf node. We also visit the same leaf node multiple times, so
|
||||
// bail out if the end of the path already points to the partition.
|
||||
auto innerSym = op->getAttrOfType<StringAttr>("inner_sym");
|
||||
auto leaf = oldPath.back().cast<hw::InnerRefAttr>();
|
||||
auto leafMod = leaf.getModule();
|
||||
auto leafSym = leaf.getName();
|
||||
if (leafSym != innerSym || leafMod == partModName)
|
||||
continue;
|
||||
|
||||
// Construct a new path starting from the old path.
|
||||
SmallVector<Attribute> newPath(oldPath.begin(), oldPath.end());
|
||||
auto lastElement = newPath.pop_back_val().cast<hw::InnerRefAttr>();
|
||||
|
||||
// Split the last element in the path to add the partition.
|
||||
auto partRef = hw::InnerRefAttr::get(partMod, partName);
|
||||
auto leafRef = hw::InnerRefAttr::get(partModName, lastElement.getName());
|
||||
|
|
|
@ -8,10 +8,15 @@ hw.globalRef @ref2 [#hw.innerNameRef<@top::@b>, #hw.innerNameRef<@B::@c>, #hw.in
|
|||
"loc" = #msft.physloc<M20K, 0, 0, 1>
|
||||
}
|
||||
|
||||
hw.globalRef @ref3 [#hw.innerNameRef<@top::@b2>, #hw.innerNameRef<@B2::@unit1>] {
|
||||
"loc" = #msft.physloc<M20K, 0, 0, 0>
|
||||
}
|
||||
|
||||
msft.module @top {} (%clk : i1) -> (out1: i2, out2: i2) {
|
||||
msft.partition @part1, "dp"
|
||||
|
||||
%res1, %_ = msft.instance @b @B(%clk) { circt.globalRef = [#hw.globalNameRef<@ref1>, #hw.globalNameRef<@ref2>], inner_sym = "b" } : (i1) -> (i2, i2)
|
||||
%res3 = msft.instance @b2 @B2(%clk) { circt.globalRef = [#hw.globalNameRef<@ref3>], inner_sym = "b2" } : (i1) -> (i2)
|
||||
|
||||
%c0 = hw.constant 0 : i2
|
||||
%res2 = msft.instance @unit1 @Extern(%c0) { targetDesignPartition = @top::@part1 }: (i2) -> (i2)
|
||||
|
@ -33,6 +38,12 @@ msft.module @B {} (%clk : i1) -> (x: i2, y: i2) {
|
|||
msft.output %2, %3: i2, i2
|
||||
}
|
||||
|
||||
msft.module @B2 {} (%clk : i1) -> (x: i2) {
|
||||
%c1 = hw.constant 1 : i2
|
||||
%0 = msft.instance @unit1 @Extern(%c1) { targetDesignPartition = @top::@part1, circt.globalRef = [#hw.globalNameRef<@ref3>], inner_sym = "unit1" }: (i2) -> (i2)
|
||||
msft.output %0 : i2
|
||||
}
|
||||
|
||||
msft.module @C {} (%in : i2) -> (out: i2) {
|
||||
%0 = msft.instance @unit3 @Extern(%in) { targetDesignPartition = @top::@part1, circt.globalRef = [#hw.globalNameRef<@ref2>], inner_sym = "unit3" } : (i2) -> (i2)
|
||||
msft.output %0 : i2
|
||||
|
@ -77,6 +88,7 @@ msft.module @Array {} (%arr_in: !hw.array<4xi5>) -> (arr_out: !hw.array<4xi5>) {
|
|||
|
||||
// CLEANUP: hw.globalRef @ref1 [#hw.innerNameRef<@top::@part1>, #hw.innerNameRef<@dp::@b.unit1>] {loc = #msft.physloc<M20K, 0, 0, 0>}
|
||||
// CLEANUP: hw.globalRef @ref2 [#hw.innerNameRef<@top::@part1>, #hw.innerNameRef<@dp::@b.c.unit3>] {loc = #msft.physloc<M20K, 0, 0, 1>}
|
||||
// CLEANUP: hw.globalRef @ref3 [#hw.innerNameRef<@top::@part1>, #hw.innerNameRef<@dp::@b2.unit1>] {loc = #msft.physloc<M20K, 0, 0, 0>}
|
||||
|
||||
// CLEANUP-LABEL: msft.module @top {} (%clk: i1) -> (out1: i2, out2: i2) {
|
||||
// CLEANUP: %part1.b.unit2.foo_x, %part1.unit1.foo_x = msft.instance @part1 @dp(%clk) {circt.globalRef = [{{.+}}], inner_sym = "part1"} : (i1) -> (i2, i2)
|
||||
|
@ -100,6 +112,7 @@ msft.module @Array {} (%arr_in: !hw.array<4xi5>) -> (arr_out: !hw.array<4xi5>) {
|
|||
// CLEANUP: %b.seq.compreg = seq.compreg %b.unit1.foo_x, %b.seq.compreg.in1 : i2
|
||||
// CLEANUP: %b.unit2.foo_x = msft.instance @b.unit2 @Extern(%b.seq.compreg) : (i2) -> i2
|
||||
// CLEANUP: %{{.+}} = msft.instance @b.c.unit3 {{.+}} {circt.globalRef = [#hw.globalNameRef<@ref2>], inner_sym = "b.c.unit3"}
|
||||
// CLEANUP: %{{.+}} = msft.instance @b2.unit1 {{.+}} {circt.globalRef = [#hw.globalNameRef<@ref3>], inner_sym = "b2.unit1"}
|
||||
// CLEANUP: %c0_i2 = hw.constant 0 : i2
|
||||
// CLEANUP: %unit1.foo_x = msft.instance @unit1 @Extern(%c0_i2) : (i2) -> i2
|
||||
// CLEANUP: msft.output %b.unit2.foo_x, %unit1.foo_x : i2, i2
|
||||
|
|
Loading…
Reference in New Issue