[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:
mikeurbach 2022-01-17 17:45:50 -07:00 committed by GitHub
parent 1f0bf86298
commit d6a959d91e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 23 deletions

View File

@ -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());

View File

@ -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