CIRCT  19.0.0git
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 
14 #include "circt/Dialect/HW/HWOps.h"
17 #include "circt/Dialect/OM/OMOps.h"
19 #include "mlir/IR/Threading.h"
20 #include "mlir/Pass/Pass.h"
21 #include "llvm/ADT/DenseMap.h"
22 
23 namespace circt {
24 namespace om {
25 #define GEN_PASS_DEF_VERIFYOBJECTFIELDS
26 #include "circt/Dialect/OM/OMPasses.h.inc"
27 } // namespace om
28 } // namespace circt
29 
30 using namespace mlir;
31 using namespace circt;
32 using namespace om;
33 
34 namespace {
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";
41  }
42 };
43 } // namespace
44 
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>();
51 
52  /// A map from a class and field name to a field.
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>()});
56 
57  // Peel tables parallelly.
58  if (failed(
59  mlir::failableParallelForEach(&getContext(), tables, [](auto &entry) {
60  ClassLike classLike = entry.first;
61  auto &table = entry.second;
62  auto result = classLike.walk([&](ClassFieldLike fieldLike)
63  -> WalkResult {
64  if (table.insert({fieldLike.getNameAttr(), fieldLike}).second)
65  return WalkResult::advance();
66 
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();
73  });
74  return LogicalResult::failure(result.wasInterrupted());
75  })))
76  return signalPassFailure();
77 
78  // Run actual verification. Make sure not to mutate `tables`.
79  auto result = mlir::failableParallelForEach(
80  &getContext(), tables, [&tables, &symbolTable](const auto &entry) {
81  ClassLike classLike = entry.first;
82  auto result =
83  classLike.walk([&](ObjectFieldOp objectField) -> WalkResult {
84  auto objectInstType =
85  cast<ClassType>(objectField.getObject().getType());
86  ClassLike classDef =
87  symbolTable.lookupNearestSymbolFrom<ClassLike>(
88  objectField, objectInstType.getClassName());
89  if (!classDef) {
90  objectField.emitError()
91  << "class " << objectInstType.getClassName()
92  << " was not found";
93  return WalkResult::interrupt();
94  }
95 
96  // Traverse the field path, verifying each field exists.
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) {
101  // Verify the field exists on the ClassOp.
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());
107 
108  if (!fieldDef) {
109  auto error =
110  objectField.emitOpError("referenced non-existent field ")
111  << field;
112  error.attachNote(classDef.getLoc()) << "class defined here";
113  return WalkResult::interrupt();
114  }
115 
116  // If there are more fields, verify the current field is of
117  // ClassType, and look up the ClassOp for that field.
118  if (i < e - 1) {
119  auto classType = dyn_cast<ClassType>(fieldDef.getType());
120  if (!classType) {
121  objectField.emitOpError("nested field access into ")
122  << field << " requires a ClassType, but found "
123  << fieldDef.getType();
124  return WalkResult::interrupt();
125  }
126 
127  // Check if the nested ClassOp exists. ObjectInstOp verifier
128  // already checked the class exits but it's not verified yet
129  // if the object is an input argument.
130  classDef = symbolTable.lookupNearestSymbolFrom<ClassLike>(
131  objectField, classType.getClassName());
132 
133  if (!classDef) {
134  objectField.emitError()
135  << "class " << classType.getClassName()
136  << " was not found";
137  return WalkResult::interrupt();
138  }
139 
140  // Proceed to the next field in the path.
141  continue;
142  }
143 
144  // On the last iteration down the path, save the final field
145  // being accessed.
146  finalField = fieldDef;
147  }
148 
149  // Verify the accessed field type matches the result type.
150  if (finalField.getType() != objectField.getResult().getType()) {
151  objectField.emitOpError("expected type ")
152  << objectField.getResult().getType()
153  << ", but accessed field has type " << finalField.getType();
154 
155  return WalkResult::interrupt();
156  }
157  return WalkResult::advance();
158  });
159  return LogicalResult::failure(result.wasInterrupted());
160  });
161  if (failed(result))
162  return signalPassFailure();
163  return markAllAnalysesPreserved();
164 }
165 
166 std::unique_ptr<mlir::Pass> circt::om::createVerifyObjectFieldsPass() {
167  return std::make_unique<VerifyObjectFieldsPass>();
168 }
assert(baseType &&"element must be base type")
std::unique_ptr< mlir::Pass > createVerifyObjectFieldsPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
Definition: emit.py:1
Definition: om.py:1