Skip to content

Commit 2fd0b29

Browse files
authored
[FIRRTL] Refactor class lowering to avoid unnecessary cloning (#7823)
1 parent 2d93ce7 commit 2fd0b29

File tree

1 file changed

+62
-24
lines changed

1 file changed

+62
-24
lines changed

lib/Dialect/FIRRTL/Transforms/LowerClasses.cpp

Lines changed: 62 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,6 +1021,7 @@ static om::ClassLike convertClass(FModuleLike moduleLike, OpBuilder builder,
10211021
fieldTypes.push_back(
10221022
NamedAttribute(name, TypeAttr::get(op.getSrc().getType())));
10231023
}
1024+
10241025
checkAddContainingModulePorts(hasContainingModule, builder, fieldNames,
10251026
fieldTypes);
10261027
return builder.create<om::ClassOp>(moduleLike.getLoc(), name,
@@ -1143,20 +1144,20 @@ void LowerClassesPass::lowerClass(om::ClassOp classOp, FModuleLike moduleLike,
11431144
for (size_t i = 0; i < nAltBasePaths; ++i)
11441145
classBody->addArgument(basePathType, unknownLoc);
11451146

1147+
// Mapping from block arguments or instance results to new values.
1148+
DenseMap<Value, Value> valueMapping;
11461149
for (auto inputProperty : inputProperties) {
11471150
BlockArgument parameterValue =
11481151
classBody->addArgument(inputProperty.type, inputProperty.loc);
11491152
BlockArgument inputValue =
11501153
moduleLike->getRegion(0).getArgument(inputProperty.index);
1151-
mapping.map(inputValue, parameterValue);
1154+
1155+
valueMapping[inputValue] = parameterValue;
11521156
}
11531157

1154-
// Clone the property ops from the FIRRTL Class or Module to the OM Class.
1155-
SmallVector<Operation *> opsToErase;
1156-
OpBuilder builder = OpBuilder::atBlockBegin(classOp.getBodyBlock());
1157-
llvm::SmallVector<mlir::Location> fieldLocs;
1158-
llvm::SmallVector<mlir::Value> fieldValues;
1159-
for (auto &op : moduleLike->getRegion(0).getOps()) {
1158+
// Helper to check if an op is a property op, which should be removed in the
1159+
// module like, or kept in the OM class.
1160+
auto isPropertyOp = [&](Operation &op) {
11601161
// Check if any operand is a property.
11611162
auto propertyOperands = llvm::any_of(op.getOperandTypes(), [](Type type) {
11621163
return isa<PropertyType>(type);
@@ -1169,28 +1170,58 @@ void LowerClassesPass::lowerClass(om::ClassOp classOp, FModuleLike moduleLike,
11691170
auto propertyResults = llvm::any_of(
11701171
op.getResultTypes(), [](Type type) { return isa<PropertyType>(type); });
11711172

1172-
// If there are no properties here, move along.
1173-
if (!needsClone && !propertyOperands && !propertyResults)
1173+
return needsClone || propertyOperands || propertyResults;
1174+
};
1175+
1176+
// Move operations from the module like to the OM class.
1177+
// We need to clone only instances and register their results to the value
1178+
// mapping. Operands must be remapped using the value mapping.
1179+
for (auto &op : llvm::make_early_inc_range(
1180+
moduleLike->getRegion(0).front().getOperations())) {
1181+
if (!isPropertyOp(op))
11741182
continue;
11751183

1176-
bool isField = false;
1184+
Operation *newOp = &op;
1185+
1186+
bool needsMove = true;
1187+
1188+
// Clone instances and register their results to the value mapping.
1189+
if (isa<InstanceOp>(op)) {
1190+
newOp = op.clone();
1191+
for (auto [oldResult, newResult] :
1192+
llvm::zip(op.getResults(), newOp->getResults()))
1193+
valueMapping[oldResult] = newResult;
1194+
classBody->getOperations().insert(classBody->end(), newOp);
1195+
needsMove = false;
1196+
}
1197+
1198+
// Remap operands using the value mapping.
1199+
for (size_t i = 0; i < newOp->getNumOperands(); ++i) {
1200+
auto operand = newOp->getOperand(i);
1201+
auto it = valueMapping.find(operand);
1202+
if (it != valueMapping.end())
1203+
newOp->setOperand(i, it->second);
1204+
}
1205+
1206+
// Move the op into the OM class body.
1207+
if (needsMove)
1208+
newOp->moveBefore(classBody, classBody->end());
1209+
}
1210+
1211+
llvm::SmallVector<mlir::Location> fieldLocs;
1212+
llvm::SmallVector<mlir::Value> fieldValues;
1213+
for (Operation &op :
1214+
llvm::make_early_inc_range(classOp.getBodyBlock()->getOperations())) {
1215+
assert(isPropertyOp(op));
1216+
11771217
if (auto propAssign = dyn_cast<PropAssignOp>(op)) {
1178-
if (isa<BlockArgument>(propAssign.getDest())) {
1218+
if (auto blockArg = dyn_cast<BlockArgument>(propAssign.getDest())) {
11791219
// Store any output property assignments into fields op inputs.
11801220
fieldLocs.push_back(op.getLoc());
1181-
fieldValues.push_back(mapping.lookup(propAssign.getSrc()));
1182-
isField = true;
1221+
fieldValues.push_back(propAssign.getSrc());
1222+
propAssign.erase();
11831223
}
11841224
}
1185-
1186-
if (!isField)
1187-
// Clone the op over to the OM Class.
1188-
builder.clone(op, mapping);
1189-
1190-
// In case this is a Module, remember to erase this op, unless it is an
1191-
// instance. Instances are handled later in updateInstances.
1192-
if (!isa<InstanceOp>(op))
1193-
opsToErase.push_back(&op);
11941225
}
11951226

11961227
// If there is a 'containingModule', add an argument for 'ports', and a field.
@@ -1201,14 +1232,21 @@ void LowerClassesPass::lowerClass(om::ClassOp classOp, FModuleLike moduleLike,
12011232
fieldValues.push_back(argumentValue);
12021233
}
12031234

1235+
OpBuilder builder = OpBuilder::atBlockEnd(classOp.getBodyBlock());
12041236
classOp.addNewFieldsOp(builder, fieldLocs, fieldValues);
12051237

12061238
// If the module-like is a Class, it will be completely erased later.
12071239
// Otherwise, erase just the property ports and ops.
12081240
if (!isa<firrtl::ClassLike>(moduleLike.getOperation())) {
12091241
// Erase ops in use before def order, thanks to FIRRTL's SSA regions.
1210-
for (auto *op : llvm::reverse(opsToErase))
1211-
op->erase();
1242+
for (auto &op :
1243+
llvm::make_early_inc_range(llvm::reverse(moduleLike.getOperation()
1244+
->getRegion(0)
1245+
.getBlocks()
1246+
.front()
1247+
.getOperations())))
1248+
if (isPropertyOp(op) && !isa<InstanceOp>(op))
1249+
op.erase();
12121250

12131251
// Erase property typed ports.
12141252
moduleLike.erasePorts(portsToErase);

0 commit comments

Comments
 (0)