[MSFT] [Design Partitioning] Bubble up wire manipulation ops also (#2426)

Towards #2365: Automatically tag "wire manipulation" ops for movement into the design partition.
This commit is contained in:
John Demme 2022-01-10 13:27:00 -08:00 committed by GitHub
parent 5426bf1556
commit 111e0662a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 137 additions and 37 deletions

View File

@ -297,6 +297,14 @@ protected:
MSFTModuleOp mod, ArrayRef<unsigned> newToOldResultMap,
llvm::function_ref<void(InstanceOp, InstanceOp, SmallVectorImpl<Value> &)>
getOperandsFunc);
static bool isWireManipulationOp(Operation *op) {
return isa<hw::ArrayConcatOp>(op) || isa<hw::ArrayCreateOp>(op) ||
isa<hw::ArrayGetOp>(op) || isa<hw::ArraySliceOp>(op) ||
isa<hw::StructCreateOp>(op) || isa<hw::StructExplodeOp>(op) ||
isa<hw::StructExtractOp>(op) || isa<hw::StructInjectOp>(op) ||
isa<hw::StructCreateOp>(op) || isa<hw::ConstantOp>(op);
}
};
} // anonymous namespace
@ -387,6 +395,9 @@ private:
void partition(DesignPartitionOp part, ArrayRef<Operation *> users);
void bubbleUp(MSFTModuleOp mod, ArrayRef<Operation *> ops);
// Tag wire manipulation ops connected to this potentially tagged op.
static void markWireOps(Operation *op);
};
} // anonymous namespace
@ -401,9 +412,42 @@ void PartitionPass::runOnOperation() {
partition(mod);
}
void PartitionPass::markWireOps(Operation *taggedOp) {
auto partRef =
taggedOp->getAttrOfType<SymbolRefAttr>("targetDesignPartition");
if (!partRef)
return;
SmallVector<Operation *, 8> opQueue;
opQueue.push_back(taggedOp);
while (!opQueue.empty()) {
Operation *op = opQueue.back();
opQueue.pop_back();
for (auto *user : op->getUsers()) {
if (!isWireManipulationOp(user) || user->hasAttr("targetDesignPartition"))
continue;
user->setAttr("targetDesignPartition", partRef);
opQueue.push_back(user);
}
for (auto operValue : op->getOperands()) {
Operation *defOp = operValue.getDefiningOp();
if (!defOp || !isWireManipulationOp(defOp) ||
defOp->hasAttr("targetDesignPartition"))
continue;
defOp->setAttr("targetDesignPartition", partRef);
opQueue.push_back(defOp);
}
}
}
void PartitionPass::partition(MSFTModuleOp mod) {
DenseMap<StringAttr, SmallVector<Operation *, 1>> localPartMembers;
SmallVector<Operation *, 64> nonLocalTaggedOps;
mod.walk(&markWireOps);
mod.walk([&](Operation *op) {
auto partRef = op->getAttrOfType<SymbolRefAttr>("targetDesignPartition");
if (!partRef)
@ -689,11 +733,6 @@ void PartitionPass::partition(DesignPartitionOp partOp,
SymbolTable::getSymbolName(partMod), partInstInputs, ArrayAttr(),
SymbolRefAttr());
// Replace original ops' outputs with partition outputs.
assert(partInstOutputs.size() == partInst.getNumResults());
for (size_t resNum = 0, e = partInstOutputs.size(); resNum < e; ++resNum)
partInstOutputs[resNum].replaceAllUsesWith(partInst.getResult(resNum));
//*************
// Move the operations!
@ -721,9 +760,16 @@ void PartitionPass::partition(DesignPartitionOp partOp,
for (size_t resNum = 0, e = op->getNumResults(); resNum < e; ++resNum)
for (int outputNum : resultOutputConnections[op->getResult(resNum)])
outputs[outputNum] = newOp->getResult(resNum);
op->erase();
}
partBuilder.create<OutputOp>(loc, outputs);
// Replace original ops' outputs with partition outputs.
assert(partInstOutputs.size() == partInst.getNumResults());
for (size_t resNum = 0, e = partInstOutputs.size(); resNum < e; ++resNum)
partInstOutputs[resNum].replaceAllUsesWith(partInst.getResult(resNum));
for (Operation *op : toMove)
op->erase();
}
namespace circt {

View File

@ -1,4 +1,3 @@
// RUN: circt-opt %s --msft-partition -verify-diagnostics -split-input-file | FileCheck %s
// RUN: circt-opt %s --msft-partition --msft-wire-cleanup -verify-diagnostics -split-input-file | FileCheck --check-prefix=CLEANUP %s
msft.module @top {} (%clk : i1) -> (out1: i2, out2: i2) {
@ -24,34 +23,89 @@ msft.module @B {} (%clk : i1) -> (x: i2) {
msft.output %2: i2
}
// CHECK-LABEL: msft.module @top {} (%clk: i1) -> (out1: i2, out2: i2) {
// CHECK: %part1.b.unit1.foo_x, %part1.b.seq.compreg.b.seq.compreg, %part1.b.unit2.foo_x, %part1.unit1.foo_x = msft.instance @part1 @dp(%b.unit1.foo_a, %b.seq.compreg.in0, %b.seq.compreg.in1, %b.unit2.foo_a, %c0_i2) : (i2, i2, i1, i2, i2) -> (i2, i2, i2, i2)
// CHECK: %b.x, %b.unit1.foo_a, %b.seq.compreg.in0, %b.seq.compreg.in1, %b.unit2.foo_a = msft.instance @b @B(%clk, %part1.b.unit1.foo_x, %part1.b.seq.compreg.b.seq.compreg, %part1.b.unit2.foo_x) : (i1, i2, i2, i2) -> (i2, i2, i2, i1, i2)
// CHECK: %c0_i2 = hw.constant 0 : i2
// CHECK: msft.output %b.x, %part1.unit1.foo_x : i2, i2
// CHECK-LABEL: msft.module.extern @Extern(%foo_a: i2) -> (foo_x: i2)
// CHECK-LABEL: msft.module @B {} (%clk: i1, %unit1.foo_x: i2, %seq.compreg: i2, %unit2.foo_x: i2) -> (x: i2, unit1.foo_a: i2, seq.compreg.in0: i2, seq.compreg.in1: i1, unit2.foo_a: i2) {
// CHECK: %c1_i2 = hw.constant 1 : i2
// CHECK: msft.output %unit2.foo_x, %c1_i2, %unit1.foo_x, %clk, %seq.compreg : i2, i2, i2, i1, i2
// CHECK-LABEL: msft.module @dp {} (%b.unit1.foo_a: i2, %b.seq.compreg.in0: i2, %b.seq.compreg.in1: i1, %b.unit2.foo_a: i2, %unit1.foo_a: i2) -> (b.unit1.foo_x: i2, b.seq.compreg.b.seq.compreg: i2, b.unit2.foo_x: i2, unit1.foo_x: i2) {
// CHECK: %b.unit1.foo_x = msft.instance @b.unit1 @Extern(%b.unit1.foo_a) : (i2) -> i2
// CHECK: %b.seq.compreg = seq.compreg %b.seq.compreg.in0, %b.seq.compreg.in1 : i2
// CHECK: %b.unit2.foo_x = msft.instance @b.unit2 @Extern(%b.unit2.foo_a) : (i2) -> i2
// CHECK: %unit1.foo_x = msft.instance @unit1 @Extern(%unit1.foo_a) : (i2) -> i2
// CHECK: msft.output %b.unit1.foo_x, %b.seq.compreg, %b.unit2.foo_x, %unit1.foo_x : i2, i2, i2, i2
msft.module @TopComplex {} (%clk : i1, %arr_in: !hw.array<4xi5>) -> (out2: i5) {
msft.partition @part2, "dp_complex"
// 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(%b.unit1.foo_a, %clk, %c0_i2) : (i2, i1, i2) -> (i2, i2)
// CLEANUP: %b.unit1.foo_a = msft.instance @b @B() : () -> i2
// CLEANUP: %c0_i2 = hw.constant 0 : i2
// CLEANUP: msft.output %part1.b.unit2.foo_x, %part1.unit1.foo_x : i2, i2
// CLEANUP-LABEL: msft.module.extern @Extern(%foo_a: i2) -> (foo_x: i2)
// CLEANUP-LABEL: msft.module @B {} () -> (unit1.foo_a: i2) {
// CLEANUP: %c1_i2 = hw.constant 1 : i2
// CLEANUP: msft.output %c1_i2 : i2
// CLEANUP-LABEL: msft.module @dp {} (%b.unit1.foo_a: i2, %b.seq.compreg.in1: i1, %unit1.foo_a: i2) -> (b.unit2.foo_x: i2, unit1.foo_x: i2)
// CLEANUP: %b.unit1.foo_x = msft.instance @b.unit1 @Extern(%b.unit1.foo_a) : (i2) -> i2
// 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: %unit1.foo_x = msft.instance @unit1 @Extern(%unit1.foo_a) : (i2) -> i2
// CLEANUP: msft.output %b.unit2.foo_x, %unit1.foo_x : i2, i2
%mut_arr = msft.instance @b @Array(%arr_in) : (!hw.array<4xi5>) -> (!hw.array<4xi5>)
%c0 = hw.constant 0 : i2
%a0 = hw.array_get %mut_arr[%c0] : !hw.array<4xi5>
%c1 = hw.constant 1 : i2
%a1 = hw.array_get %mut_arr[%c1] : !hw.array<4xi5>
%c2 = hw.constant 2 : i2
%a2 = hw.array_get %mut_arr[%c2] : !hw.array<4xi5>
%c3 = hw.constant 3 : i2
%a3 = hw.array_get %mut_arr[%c3] : !hw.array<4xi5>
%res1 = comb.add %a0, %a1, %a2, %a3 { targetDesignPartition = @TopComplex::@part2 } : i5
msft.output %res1 : i5
}
msft.module.extern @ExternI5 (%foo_a: i5) -> (foo_x: i5)
msft.module @Array {} (%arr_in: !hw.array<4xi5>) -> (arr_out: !hw.array<4xi5>) {
%c0 = hw.constant 0 : i2
%in0 = hw.array_get %arr_in[%c0] : !hw.array<4xi5>
%out0 = msft.instance @unit2 @ExternI5(%in0) { targetDesignPartition = @TopComplex::@part2 }: (i5) -> (i5)
%c1 = hw.constant 1 : i2
%in1 = hw.array_get %arr_in[%c1] : !hw.array<4xi5>
%out1 = msft.instance @unit2 @ExternI5(%in1) { targetDesignPartition = @TopComplex::@part2 }: (i5) -> (i5)
%c2 = hw.constant 2 : i2
%in2 = hw.array_get %arr_in[%c2] : !hw.array<4xi5>
%out2 = msft.instance @unit2 @ExternI5(%in2) { targetDesignPartition = @TopComplex::@part2 }: (i5) -> (i5)
%c3 = hw.constant 3 : i2
%in3 = hw.array_get %arr_in[%c3] : !hw.array<4xi5>
%out3 = msft.instance @unit2 @ExternI5(%in3) { targetDesignPartition = @TopComplex::@part2 }: (i5) -> (i5)
%arr_out = hw.array_create %out0, %out1, %out2, %out3 : i5
msft.output %arr_out : !hw.array<4xi5>
}
// 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) : (i1) -> (i2, i2)
// CLEANUP: msft.instance @b @B() : () -> ()
// CLEANUP: msft.output %part1.b.unit2.foo_x, %part1.unit1.foo_x : i2, i2
// CLEANUP-LABEL: msft.module.extern @Extern(%foo_a: i2) -> (foo_x: i2)
// CLEANUP-LABEL: msft.module @B {} ()
// CLEANUP: msft.output
// CLEANUP-LABEL: msft.module @TopComplex {} (%arr_in: !hw.array<4xi5>) -> (out2: i5)
// CLEANUP: %part2.comb.add = msft.instance @part2 @dp_complex(%arr_in, %arr_in, %arr_in, %arr_in) : (!hw.array<4xi5>, !hw.array<4xi5>, !hw.array<4xi5>, !hw.array<4xi5>) -> i5
// CLEANUP: msft.instance @b @Array() : () -> ()
// CLEANUP: msft.output %part2.comb.add : i5
// CLEANUP-LABEL: msft.module.extern @ExternI5(%foo_a: i5) -> (foo_x: i5)
// CLEANUP-LABEL: msft.module @Array {} ()
// CLEANUP: msft.output
// CLEANUP-LABEL: msft.module @dp {} (%b.seq.compreg.in1: i1) -> (b.unit2.foo_x: i2, unit1.foo_x: i2) {
// CLEANUP: %c1_i2 = hw.constant 1 : i2
// CLEANUP: %b.unit1.foo_x = msft.instance @b.unit1 @Extern(%c1_i2) : (i2) -> i2
// 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: %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
// CLEANUP-LABEL: msft.module @dp_complex {} (%hw.array_get.in0: !hw.array<4xi5>, %hw.array_get.in0_0: !hw.array<4xi5>, %hw.array_get.in0_1: !hw.array<4xi5>, %hw.array_get.in0_2: !hw.array<4xi5>) -> (comb.add: i5) attributes {argNames = ["hw.array_get.in0", "hw.array_get.in0", "hw.array_get.in0", "hw.array_get.in0"]} {
// CLEANUP: %c0_i2 = hw.constant 0 : i2
// CLEANUP: %0 = hw.array_get %hw.array_get.in0[%c0_i2] : !hw.array<4xi5>
// CLEANUP: %b.unit2.foo_x = msft.instance @b.unit2 @ExternI5(%0) : (i5) -> i5
// CLEANUP: %c1_i2 = hw.constant 1 : i2
// CLEANUP: %1 = hw.array_get %hw.array_get.in0_0[%c1_i2] : !hw.array<4xi5>
// CLEANUP: %b.unit2.foo_x_3 = msft.instance @b.unit2 @ExternI5(%1) : (i5) -> i5
// CLEANUP: %c-2_i2 = hw.constant -2 : i2
// CLEANUP: %2 = hw.array_get %hw.array_get.in0_1[%c-2_i2] : !hw.array<4xi5>
// CLEANUP: %b.unit2.foo_x_4 = msft.instance @b.unit2 @ExternI5(%2) : (i5) -> i5
// CLEANUP: %c-1_i2 = hw.constant -1 : i2
// CLEANUP: %3 = hw.array_get %hw.array_get.in0_2[%c-1_i2] : !hw.array<4xi5>
// CLEANUP: %b.unit2.foo_x_5 = msft.instance @b.unit2 @ExternI5(%3) : (i5) -> i5
// CLEANUP: %4 = hw.array_create %b.unit2.foo_x, %b.unit2.foo_x_3, %b.unit2.foo_x_4, %b.unit2.foo_x_5 : i5
// CLEANUP: %c0_i2_6 = hw.constant 0 : i2
// CLEANUP: %5 = hw.array_get %4[%c0_i2_6] : !hw.array<4xi5>
// CLEANUP: %c1_i2_7 = hw.constant 1 : i2
// CLEANUP: %6 = hw.array_get %4[%c1_i2_7] : !hw.array<4xi5>
// CLEANUP: %c-2_i2_8 = hw.constant -2 : i2
// CLEANUP: %7 = hw.array_get %4[%c-2_i2_8] : !hw.array<4xi5>
// CLEANUP: %c-1_i2_9 = hw.constant -1 : i2
// CLEANUP: %8 = hw.array_get %4[%c-1_i2_9] : !hw.array<4xi5>
// CLEANUP: %9 = comb.add %5, %6, %7, %8 : i5
// CLEANUP: msft.output %9 : i5