19 #include "mlir/IR/Threading.h"
20 #include "mlir/Pass/Pass.h"
21 #include "llvm/ADT/DenseMap.h"
25 #define GEN_PASS_DEF_VERIFYOBJECTFIELDS
26 #include "circt/Dialect/OM/OMPasses.h.inc"
31 using namespace circt;
35 struct VerifyObjectFieldsPass
36 :
public circt::om::impl::VerifyObjectFieldsBase<VerifyObjectFieldsPass> {
37 void runOnOperation()
override;
38 bool canScheduleOn(RegisteredOperationName opName)
const override {
39 return opName.getStringRef() ==
"firrtl.circuit" ||
40 opName.getStringRef() ==
"builtin.module";
45 void VerifyObjectFieldsPass::runOnOperation() {
46 auto *module = getOperation();
47 assert(module->getNumRegions() == 1 &&
48 module->hasTrait<OpTrait::SymbolTable>() &&
49 "op must have a single region and symbol table trait");
50 auto &symbolTable = getAnalysis<SymbolTable>();
53 llvm::MapVector<ClassLike, llvm::DenseMap<StringAttr, ClassFieldLike>> tables;
54 for (
auto op : module->getRegion(0).getOps<om::ClassLike>())
55 tables.insert({op, llvm::DenseMap<StringAttr, ClassFieldLike>()});
59 mlir::failableParallelForEach(&getContext(), tables, [](
auto &entry) {
60 ClassLike classLike = entry.first;
61 auto &table = entry.second;
62 auto result = classLike.walk([&](ClassFieldLike fieldLike)
64 if (table.insert({fieldLike.getNameAttr(), fieldLike}).second)
65 return WalkResult::advance();
67 auto emit = fieldLike.emitOpError()
68 <<
"field " << fieldLike.getNameAttr()
69 <<
" is defined twice";
70 emit.attachNote(table.lookup(fieldLike.getNameAttr()).getLoc())
71 <<
"previous definition is here";
72 return WalkResult::interrupt();
74 return LogicalResult::failure(result.wasInterrupted());
76 return signalPassFailure();
79 auto result = mlir::failableParallelForEach(
80 &getContext(), tables, [&tables, &symbolTable](
const auto &entry) {
81 ClassLike classLike = entry.first;
83 classLike.walk([&](ObjectFieldOp objectField) -> WalkResult {
85 cast<ClassType>(objectField.getObject().getType());
87 symbolTable.lookupNearestSymbolFrom<ClassLike>(
88 objectField, objectInstType.getClassName());
90 objectField.emitError()
91 <<
"class " << objectInstType.getClassName()
93 return WalkResult::interrupt();
97 ClassFieldLike finalField;
98 auto fields = SmallVector<FlatSymbolRefAttr>(
99 objectField.getFieldPath().getAsRange<FlatSymbolRefAttr>());
100 for (
size_t i = 0, e = fields.size(); i < e; ++i) {
102 auto field = fields[i];
103 ClassFieldLike fieldDef;
104 auto *it = tables.find(classDef);
105 assert(it != tables.end() &&
"must be visited");
106 fieldDef = it->second.lookup(field.getAttr());
110 objectField.emitOpError(
"referenced non-existent field ")
112 error.attachNote(classDef.getLoc()) <<
"class defined here";
113 return WalkResult::interrupt();
119 auto classType = dyn_cast<ClassType>(fieldDef.getType());
121 objectField.emitOpError(
"nested field access into ")
122 << field <<
" requires a ClassType, but found "
123 << fieldDef.getType();
124 return WalkResult::interrupt();
130 classDef = symbolTable.lookupNearestSymbolFrom<ClassLike>(
131 objectField, classType.getClassName());
134 objectField.emitError()
135 <<
"class " << classType.getClassName()
137 return WalkResult::interrupt();
146 finalField = fieldDef;
150 if (finalField.getType() != objectField.getResult().getType()) {
151 objectField.emitOpError(
"expected type ")
152 << objectField.getResult().getType()
153 <<
", but accessed field has type " << finalField.getType();
155 return WalkResult::interrupt();
157 return WalkResult::advance();
159 return LogicalResult::failure(result.wasInterrupted());
162 return signalPassFailure();
163 return markAllAnalysesPreserved();
167 return std::make_unique<VerifyObjectFieldsPass>();
assert(baseType &&"element must be base type")
std::unique_ptr< mlir::Pass > createVerifyObjectFieldsPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.