[OM] Preserve non-OM operations in OM LinkModules (#8109)

This commit changes OM LinkModule pass to preserve non-OM operations.
This commit is contained in:
Hideto Ueno 2025-01-22 12:56:06 -08:00 committed by GitHub
parent 19f9af004b
commit 8ec4b69d7f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 38 additions and 11 deletions

View File

@ -13,6 +13,7 @@
#include "circt/Dialect/OM/OMOps.h"
#include "circt/Dialect/OM/OMPasses.h"
#include "circt/Support/Namespace.h"
#include "mlir/IR/Block.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/SymbolTable.h"
@ -39,7 +40,9 @@ using SymMappingTy =
llvm::DenseMap<std::pair<ModuleOp, StringAttr>, StringAttr>;
struct ModuleInfo {
ModuleInfo(mlir::ModuleOp module) : module(module) {}
ModuleInfo(mlir::ModuleOp module) : module(module) {
block = std::make_unique<Block>();
}
// Populate `symbolToClasses`.
LogicalResult initialize();
@ -52,6 +55,9 @@ struct ModuleInfo {
// A target module.
ModuleOp module;
// A block to store original operations.
std::unique_ptr<Block> block;
};
struct LinkModulesPass
@ -65,8 +71,10 @@ LogicalResult ModuleInfo::initialize() {
for (auto &op : llvm::make_early_inc_range(module.getOps())) {
if (auto classLike = dyn_cast<ClassLike>(op))
symbolToClasses.insert({classLike.getSymNameAttr(), classLike});
else
op.erase();
else {
// Keep the op.
op.moveBefore(block.get(), block->end());
}
}
return success();
}
@ -293,11 +301,13 @@ void LinkModulesPass::runOnOperation() {
// Finally move operations to the toplevel module.
auto *block = toplevelModule.getBody();
for (auto info : modules) {
for (auto &info : modules) {
block->getOperations().splice(block->end(),
info.module.getBody()->getOperations());
// Erase the module.
info.module.erase();
// Restore non-OM operations.
assert(info.module.getBody()->empty());
info.module.getBody()->getOperations().splice(
info.module.getBody()->begin(), info.block->getOperations());
}
}

View File

@ -2,7 +2,7 @@
module {
// CHECK-LABEL: module
// CHECK-NOT: module
// CHECK-NEXT: module
// CHECK-NOT: om.class.extern
// CHECK-LABEL: om.class @A
// CHECK-LABEL: om.class @Conflict_A
@ -61,12 +61,12 @@ module {
// -----
// Check that OM ops are deleted. Make the "delete-me" op a landmine that will
// cause a symbol collision if it is _not_ deleted.
// Check that OM ops are not deleted. Make the "dont-delete-me" op a landmine that will
// cause a symbol collision if it is moved to the top level.
module {
module {
// CHECK-NOT: delete-me
"delete-me"() {sym_name = "Bar"} : () -> ()
// CHECK: dont-delete-me
"dont-delete-me"() {sym_name = "Bar"} : () -> ()
om.class @Foo() {
om.class.fields
}

View File

@ -5,4 +5,5 @@ module {
om.class @Conflict(){
om.class.fields
}
hw.module @hello() {}
}

View File

@ -6,4 +6,5 @@ module {
om.class @Conflict(){
om.class.fields
}
hw.module.extern @hello()
}

View File

@ -1,5 +1,20 @@
// RUN: om-linker %S/Inputs/a.mlir %S/Inputs/b.mlir %S/Inputs/other.mlir | FileCheck %s
// CHECK: module {
// CHECK-NEXT: module attributes {om.namespace = "a"} {
// CHECK-NEXT: hw.module @hello() {
// CHECK-NEXT: hw.output
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: module attributes {om.namespace = "b"} {
// CHECK-NEXT: hw.module.extern @hello()
// CHECK-NEXT: }
// CHECK-NEXT: module attributes {om.namespace = "other"} {
// CHECK-NEXT: hw.module @HW(in %a : i1, out b : i1) {
// CHECK: hw.output
// CHECK-NEXT: }
// CHECK-NEXT: emit.file "foo.sv" sym @Emit {
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: om.class @A(%arg: i1) {
// CHECK-NEXT: om.class.fields
// CHECK-NEXT: }