CIRCT 20.0.0git
Loading...
Searching...
No Matches
VerifyObjectFields.cpp
Go to the documentation of this file.
1//===- VerifyObjectFields.cpp - Verify Object fields -------------*- C++-*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Contains the definitions of the OM verify object fields pass.
10//
11//===----------------------------------------------------------------------===//
12
19#include "mlir/IR/Threading.h"
20#include "mlir/Pass/Pass.h"
21#include "llvm/ADT/DenseMap.h"
22
23namespace circt {
24namespace om {
25#define GEN_PASS_DEF_VERIFYOBJECTFIELDS
26#include "circt/Dialect/OM/OMPasses.h.inc"
27} // namespace om
28} // namespace circt
29
30using namespace mlir;
31using namespace circt;
32using namespace om;
33
34namespace {
35struct 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";
41 }
42};
43} // namespace
44
45void 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>();
51
52 // Run actual verification. Make sure not to mutate `tables`.
53 auto result = mlir::failableParallelForEach(
54 &getContext(), module->getRegion(0).getOps<om::ClassLike>(),
55 [&symbolTable](ClassLike classLike) {
56 auto result =
57 classLike.walk([&](ObjectFieldOp objectField) -> WalkResult {
58 auto objectInstType =
59 cast<ClassType>(objectField.getObject().getType());
60 ClassLike classDef =
61 symbolTable.lookupNearestSymbolFrom<ClassLike>(
62 objectField, objectInstType.getClassName());
63 if (!classDef) {
64 objectField.emitError()
65 << "class " << objectInstType.getClassName()
66 << " was not found";
67 return WalkResult::interrupt();
68 }
69
70 // Traverse the field path, verifying each field exists.
71 Type finalFieldType;
72 auto fields = SmallVector<FlatSymbolRefAttr>(
73 objectField.getFieldPath().getAsRange<FlatSymbolRefAttr>());
74 for (size_t i = 0, e = fields.size(); i < e; ++i) {
75 // Verify the field exists on the ClassOp.
76 auto field = fields[i];
77 std::optional<Type> fieldTypeOpt =
78 classDef.getFieldType(field.getAttr());
79
80 if (!fieldTypeOpt.has_value()) {
81 auto error =
82 objectField.emitOpError("referenced non-existent field ")
83 << field;
84 error.attachNote(classDef.getLoc()) << "class defined here";
85 return WalkResult::interrupt();
86 }
87 Type fieldType = fieldTypeOpt.value();
88
89 // If there are more fields, verify the current field is of
90 // ClassType, and look up the ClassOp for that field.
91 if (i < e - 1) {
92 auto classType = dyn_cast<ClassType>(fieldType);
93 if (!classType) {
94 objectField.emitOpError("nested field access into ")
95 << field << " requires a ClassType, but found "
96 << fieldType;
97 return WalkResult::interrupt();
98 }
99
100 // Check if the nested ClassOp exists. ObjectInstOp verifier
101 // already checked the class exits but it's not verified yet
102 // if the object is an input argument.
103 classDef = symbolTable.lookupNearestSymbolFrom<ClassOp>(
104 objectField, classType.getClassName());
105
106 if (!classDef) {
107 objectField.emitError()
108 << "class " << classType.getClassName()
109 << " was not found";
110 return WalkResult::interrupt();
111 }
112
113 // Proceed to the next field in the path.
114 continue;
115 }
116
117 // On the last iteration down the path, save the final field
118 // being accessed.
119 finalFieldType = fieldType;
120 }
121
122 // Verify the accessed field type matches the result type.
123 if (finalFieldType != objectField.getResult().getType()) {
124 objectField.emitOpError("expected type ")
125 << objectField.getResult().getType()
126 << ", but accessed field has type " << finalFieldType;
127
128 return WalkResult::interrupt();
129 }
130 return WalkResult::advance();
131 });
132 return LogicalResult::failure(result.wasInterrupted());
133 });
134 if (failed(result))
135 return signalPassFailure();
136 return markAllAnalysesPreserved();
137}
138
139std::unique_ptr<mlir::Pass> circt::om::createVerifyObjectFieldsPass() {
140 return std::make_unique<VerifyObjectFieldsPass>();
141}
assert(baseType &&"element must be base type")
std::unique_ptr< mlir::Pass > createVerifyObjectFieldsPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition om.py:1