@@ -1021,6 +1021,7 @@ static om::ClassLike convertClass(FModuleLike moduleLike, OpBuilder builder,
1021
1021
fieldTypes.push_back (
1022
1022
NamedAttribute (name, TypeAttr::get (op.getSrc ().getType ())));
1023
1023
}
1024
+
1024
1025
checkAddContainingModulePorts (hasContainingModule, builder, fieldNames,
1025
1026
fieldTypes);
1026
1027
return builder.create <om::ClassOp>(moduleLike.getLoc (), name,
@@ -1143,20 +1144,20 @@ void LowerClassesPass::lowerClass(om::ClassOp classOp, FModuleLike moduleLike,
1143
1144
for (size_t i = 0 ; i < nAltBasePaths; ++i)
1144
1145
classBody->addArgument (basePathType, unknownLoc);
1145
1146
1147
+ // Mapping from block arguments or instance results to new values.
1148
+ DenseMap<Value, Value> valueMapping;
1146
1149
for (auto inputProperty : inputProperties) {
1147
1150
BlockArgument parameterValue =
1148
1151
classBody->addArgument (inputProperty.type , inputProperty.loc );
1149
1152
BlockArgument inputValue =
1150
1153
moduleLike->getRegion (0 ).getArgument (inputProperty.index );
1151
- mapping.map (inputValue, parameterValue);
1154
+
1155
+ valueMapping[inputValue] = parameterValue;
1152
1156
}
1153
1157
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) {
1160
1161
// Check if any operand is a property.
1161
1162
auto propertyOperands = llvm::any_of (op.getOperandTypes (), [](Type type) {
1162
1163
return isa<PropertyType>(type);
@@ -1169,28 +1170,58 @@ void LowerClassesPass::lowerClass(om::ClassOp classOp, FModuleLike moduleLike,
1169
1170
auto propertyResults = llvm::any_of (
1170
1171
op.getResultTypes (), [](Type type) { return isa<PropertyType>(type); });
1171
1172
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))
1174
1182
continue ;
1175
1183
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
+
1177
1217
if (auto propAssign = dyn_cast<PropAssignOp>(op)) {
1178
- if (isa <BlockArgument>(propAssign.getDest ())) {
1218
+ if (auto blockArg = dyn_cast <BlockArgument>(propAssign.getDest ())) {
1179
1219
// Store any output property assignments into fields op inputs.
1180
1220
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 () ;
1183
1223
}
1184
1224
}
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);
1194
1225
}
1195
1226
1196
1227
// 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,
1201
1232
fieldValues.push_back (argumentValue);
1202
1233
}
1203
1234
1235
+ OpBuilder builder = OpBuilder::atBlockEnd (classOp.getBodyBlock ());
1204
1236
classOp.addNewFieldsOp (builder, fieldLocs, fieldValues);
1205
1237
1206
1238
// If the module-like is a Class, it will be completely erased later.
1207
1239
// Otherwise, erase just the property ports and ops.
1208
1240
if (!isa<firrtl::ClassLike>(moduleLike.getOperation ())) {
1209
1241
// 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 ();
1212
1250
1213
1251
// Erase property typed ports.
1214
1252
moduleLike.erasePorts (portsToErase);
0 commit comments