16#include "mlir/IR/Block.h"
17#include "mlir/IR/Builders.h"
18#include "mlir/IR/BuiltinOps.h"
19#include "mlir/IR/SymbolTable.h"
20#include "mlir/IR/Threading.h"
21#include "mlir/Pass/Pass.h"
22#include "llvm/ADT/TypeSwitch.h"
28#define GEN_PASS_DEF_LINKMODULES
29#include "circt/Dialect/OM/OMPasses.h.inc"
40 llvm::DenseMap<std::pair<ModuleOp, StringAttr>, StringAttr>;
43 ModuleInfo(mlir::ModuleOp module) : module(module) {
44 block = std::make_unique<Block>();
48 LogicalResult initialize();
51 void postProcess(
const SymMappingTy &symMapping);
54 llvm::DenseMap<StringAttr, ClassLike> symbolToClasses;
60 std::unique_ptr<Block> block;
64 :
public circt::om::impl::LinkModulesBase<LinkModulesPass> {
66 void runOnOperation()
override;
71LogicalResult ModuleInfo::initialize() {
72 for (
auto &op : llvm::make_early_inc_range(module.getOps())) {
73 if (
auto classLike = dyn_cast<ClassLike>(op))
74 symbolToClasses.insert({classLike.getSymNameAttr(), classLike});
77 op.moveBefore(block.get(), block->end());
83void ModuleInfo::postProcess(
const SymMappingTy &symMapping) {
84 AttrTypeReplacer replacer;
85 replacer.addReplacement(
87 [&](om::ClassType classType) -> std::pair<mlir::Type, WalkResult> {
88 auto it = symMapping.find({module, classType.getClassName().getAttr()});
90 if (it == symMapping.end())
91 return {classType, WalkResult::skip()};
92 return {om::ClassType::get(classType.getContext(),
93 FlatSymbolRefAttr::get(it->second)),
97 module.walk<WalkOrder::PreOrder>([&](Operation *op) {
99 if (isa<ClassExternOp>(op)) {
102 return WalkResult::skip();
105 llvm::TypeSwitch<Operation *>(op)
106 .Case<ClassOp>([&](ClassOp classOp) {
107 auto it = symMapping.find({module, classOp.getNameAttr()});
109 if (it != symMapping.end())
110 classOp.setSymNameAttr(it->second);
112 .Case<ObjectOp, ElaboratedObjectOp>([&](
auto objectLike) {
113 auto it = symMapping.find(
114 {module, objectLike.getClassNameAttr().getAttr()});
116 if (it != symMapping.end())
117 objectLike.setClassNameAttr(FlatSymbolRefAttr::get(it->second));
121 replacer.replaceElementsIn(op,
125 return WalkResult::advance();
132 ArrayRef<ClassLike> classes) {
133 bool existExternalClass =
false;
134 size_t countDefinition = 0;
137 for (
auto op : classes) {
138 if (isa<ClassExternOp>(op))
139 existExternalClass =
true;
141 classOp = cast<ClassOp>(op);
148 if (existExternalClass && countDefinition != 1) {
149 SmallVector<Location> classExternLocs;
150 SmallVector<Location> classLocs;
151 for (
auto op : classes)
152 (isa<ClassExternOp>(op) ? classExternLocs : classLocs)
153 .push_back(op.getLoc());
155 auto diag = emitError(classExternLocs.front())
156 <<
"class " << name <<
" is declared as an external class but "
157 << (countDefinition == 0 ?
"there is no definition"
158 :
"there are multiple definitions");
159 for (
auto loc : ArrayRef(classExternLocs).drop_front())
160 diag.attachNote(loc) <<
"class " << name <<
" is declared here as well";
162 if (countDefinition != 0) {
164 for (
auto loc : classLocs)
165 diag.attachNote(loc) <<
"class " << name <<
" is defined here";
170 if (!existExternalClass)
171 return countDefinition != 1;
173 assert(classOp && countDefinition == 1);
177 auto emitError = [&](Operation *op) {
178 auto diag = op->emitError()
179 <<
"failed to link class " << name
180 <<
" since declaration doesn't match the definition: ";
181 diag.attachNote(classOp.getLoc()) <<
"definition is here";
185 for (
auto op : classes) {
189 if (classOp.getBodyBlock()->getNumArguments() !=
190 op.getBodyBlock()->getNumArguments())
191 return emitError(op) <<
"the number of arguments is not equal, "
192 << classOp.getBodyBlock()->getNumArguments()
193 <<
" vs " << op.getBodyBlock()->getNumArguments();
195 for (
auto [l, r] : llvm::zip(classOp.getBodyBlock()->getArgumentTypes(),
196 op.getBodyBlock()->getArgumentTypes())) {
198 return emitError(op) << index <<
"-th argument type is not equal, " << l
203 llvm::DenseSet<StringAttr> declaredFields;
205 for (
auto nameAttr : op.getFieldNames()) {
206 StringAttr name = cast<StringAttr>(nameAttr);
207 std::optional<Type> opTypeOpt = op.getFieldType(name);
209 if (!opTypeOpt.has_value())
210 return emitError(op) <<
" no type for field " << name;
211 Type opType = opTypeOpt.value();
213 std::optional<Type> classTypeOpt = classOp.getFieldType(name);
216 if (!classTypeOpt.has_value())
217 return emitError(op) <<
"declaration has a field " << name
218 <<
" but not found in its definition";
219 Type classType = classTypeOpt.value();
221 if (classType != opType)
223 <<
"declaration has a field " << name
224 <<
" but types don't match, " << classType <<
" vs " << opType;
225 declaredFields.insert(name);
228 for (
auto fieldName : classOp.getFieldNames())
229 if (!declaredFields.count(cast<StringAttr>(fieldName)))
230 return emitError(op) <<
"definition has a field " << fieldName
231 <<
" but not found in this declaration";
236void LinkModulesPass::runOnOperation() {
237 auto toplevelModule = getOperation();
239 SmallVector<ModuleInfo> modules;
241 for (
auto module : toplevelModule.getOps<ModuleOp>()) {
242 auto name =
module->getAttrOfType<StringAttr>("om.namespace");
245 name = StringAttr::get(module.getContext(),
"module_" + Twine(counter++));
246 module->setAttr("om.namespace", name);
248 modules.emplace_back(module);
251 if (failed(failableParallelForEach(&getContext(), modules, [](
auto &info) {
253 return info.initialize();
255 return signalPassFailure();
263 SymMappingTy symMapping;
266 llvm::MapVector<StringAttr, SmallVector<ClassLike>> symbolToClasses;
267 for (
const auto &info : modules)
268 for (
auto &[name, op] :
info.symbolToClasses) {
269 symbolToClasses[name].push_back(op);
271 (void)nameSpace.
newName(name.getValue());
278 for (
auto &[name, classes] : symbolToClasses) {
283 return signalPassFailure();
289 for (
auto op : classes) {
290 auto enclosingModule = cast<mlir::ModuleOp>(op->getParentOp());
292 enclosingModule->getAttrOfType<StringAttr>(
"om.namespace");
293 symMapping[{enclosingModule, name}] = StringAttr::get(
295 nameSpace.
newName(name.getValue(), nameSpaceId.getValue()));
302 parallelForEach(&getContext(), modules,
303 [&](
auto &info) {
info.postProcess(symMapping); });
306 auto *block = toplevelModule.getBody();
307 for (
auto &info : modules) {
308 block->getOperations().splice(block->end(),
309 info.module.getBody()->getOperations());
312 info.module.getBody()->getOperations().splice(
313 info.module.getBody()->begin(),
info.block->getOperations());
assert(baseType &&"element must be base type")
static FailureOr< bool > resolveClasses(StringAttr name, ArrayRef< ClassLike > classes)
false return failure()
Parse an optional keyword or string and set instance into 'result'.
StringRef newName(const Twine &name)
Return a unique name, derived from the input name, and add the new name to the internal namespace.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.