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 auto result = mlir::failableParallelForEach(
54 &getContext(), module->getRegion(0).getOps<om::ClassLike>(),
55 [&symbolTable](ClassLike classLike) {
57 classLike.walk([&](ObjectFieldOp objectField) -> WalkResult {
59 cast<ClassType>(objectField.getObject().getType());
61 symbolTable.lookupNearestSymbolFrom<ClassLike>(
62 objectField, objectInstType.getClassName());
64 objectField.emitError()
65 <<
"class " << objectInstType.getClassName()
67 return WalkResult::interrupt();
72 auto fields = SmallVector<FlatSymbolRefAttr>(
73 objectField.getFieldPath().getAsRange<FlatSymbolRefAttr>());
74 for (size_t i = 0, e = fields.size(); i < e; ++i) {
76 auto field = fields[i];
77 std::optional<Type> fieldTypeOpt =
78 classDef.getFieldType(field.getAttr());
80 if (!fieldTypeOpt.has_value()) {
82 objectField.emitOpError(
"referenced non-existent field ")
84 error.attachNote(classDef.getLoc()) <<
"class defined here";
85 return WalkResult::interrupt();
87 Type fieldType = fieldTypeOpt.value();
92 auto classType = dyn_cast<ClassType>(fieldType);
94 objectField.emitOpError(
"nested field access into ")
95 << field <<
" requires a ClassType, but found "
97 return WalkResult::interrupt();
103 classDef = symbolTable.lookupNearestSymbolFrom<ClassOp>(
104 objectField, classType.getClassName());
107 objectField.emitError()
108 <<
"class " << classType.getClassName()
110 return WalkResult::interrupt();
119 finalFieldType = fieldType;
123 if (finalFieldType != objectField.getResult().getType()) {
124 objectField.emitOpError(
"expected type ")
125 << objectField.getResult().getType()
126 <<
", but accessed field has type " << finalFieldType;
128 return WalkResult::interrupt();
130 return WalkResult::advance();
132 return LogicalResult::failure(result.wasInterrupted());
135 return signalPassFailure();
136 return markAllAnalysesPreserved();
140 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.