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 
13 #include "PassDetails.h"
15 #include "circt/Dialect/HW/HWOps.h"
18 #include "circt/Dialect/OM/OMOps.h"
20 #include "mlir/IR/Threading.h"
21 #include "llvm/ADT/DenseMap.h"
22 
23 using namespace mlir;
24 using namespace circt;
25 using namespace om;
26 
27 namespace {
28 struct VerifyObjectFieldsPass
29  : public VerifyObjectFieldsBase<VerifyObjectFieldsPass> {
30  void runOnOperation() override;
31  bool canScheduleOn(RegisteredOperationName opName) const override {
32  return opName.getStringRef() == "firrtl.circuit" ||
33  opName.getStringRef() == "builtin.module";
34  }
35 };
36 } // namespace
37 
38 void VerifyObjectFieldsPass::runOnOperation() {
39  auto *module = getOperation();
40  assert(module->getNumRegions() == 1 &&
41  module->hasTrait<OpTrait::SymbolTable>() &&
42  "op must have a single region and symbol table trait");
43  auto &symbolTable = getAnalysis<SymbolTable>();
44 
45  /// A map from a class and field name to a field.
46  llvm::MapVector<ClassLike, llvm::DenseMap<StringAttr, ClassFieldLike>> tables;
47  for (auto op : module->getRegion(0).getOps<om::ClassLike>())
48  tables.insert({op, llvm::DenseMap<StringAttr, ClassFieldLike>()});
49 
50  // Peel tables parallelly.
51  if (failed(
52  mlir::failableParallelForEach(&getContext(), tables, [](auto &entry) {
53  ClassLike classLike = entry.first;
54  auto &table = entry.second;
55  auto result = classLike.walk([&](ClassFieldLike fieldLike)
56  -> WalkResult {
57  if (table.insert({fieldLike.getNameAttr(), fieldLike}).second)
58  return WalkResult::advance();
59 
60  auto emit = fieldLike.emitOpError()
61  << "field " << fieldLike.getNameAttr()
62  << " is defined twice";
63  emit.attachNote(table.lookup(fieldLike.getNameAttr()).getLoc())
64  << "previous definition is here";
65  return WalkResult::interrupt();
66  });
67  return LogicalResult::failure(result.wasInterrupted());
68  })))
69  return signalPassFailure();
70 
71  // Run actual verification. Make sure not to mutate `tables`.
72  auto result = mlir::failableParallelForEach(
73  &getContext(), tables, [&tables, &symbolTable](const auto &entry) {
74  ClassLike classLike = entry.first;
75  auto result =
76  classLike.walk([&](ObjectFieldOp objectField) -> WalkResult {
77  auto objectInstType =
78  cast<ClassType>(objectField.getObject().getType());
79  ClassLike classDef =
80  symbolTable.lookupNearestSymbolFrom<ClassLike>(
81  objectField, objectInstType.getClassName());
82  if (!classDef) {
83  objectField.emitError()
84  << "class " << objectInstType.getClassName()
85  << " was not found";
86  return WalkResult::interrupt();
87  }
88 
89  // Traverse the field path, verifying each field exists.
90  ClassFieldLike finalField;
91  auto fields = SmallVector<FlatSymbolRefAttr>(
92  objectField.getFieldPath().getAsRange<FlatSymbolRefAttr>());
93  for (size_t i = 0, e = fields.size(); i < e; ++i) {
94  // Verify the field exists on the ClassOp.
95  auto field = fields[i];
96  ClassFieldLike fieldDef;
97  auto *it = tables.find(classDef);
98  assert(it != tables.end() && "must be visited");
99  fieldDef = it->second.lookup(field.getAttr());
100 
101  if (!fieldDef) {
102  auto error =
103  objectField.emitOpError("referenced non-existent field ")
104  << field;
105  error.attachNote(classDef.getLoc()) << "class defined here";
106  return WalkResult::interrupt();
107  }
108 
109  // If there are more fields, verify the current field is of
110  // ClassType, and look up the ClassOp for that field.
111  if (i < e - 1) {
112  auto classType = dyn_cast<ClassType>(fieldDef.getType());
113  if (!classType) {
114  objectField.emitOpError("nested field access into ")
115  << field << " requires a ClassType, but found "
116  << fieldDef.getType();
117  return WalkResult::interrupt();
118  }
119 
120  // Check if the nested ClassOp exists. ObjectInstOp verifier
121  // already checked the class exits but it's not verified yet
122  // if the object is an input argument.
123  classDef = symbolTable.lookupNearestSymbolFrom<ClassLike>(
124  objectField, classType.getClassName());
125 
126  if (!classDef) {
127  objectField.emitError()
128  << "class " << classType.getClassName()
129  << " was not found";
130  return WalkResult::interrupt();
131  }
132 
133  // Proceed to the next field in the path.
134  continue;
135  }
136 
137  // On the last iteration down the path, save the final field
138  // being accessed.
139  finalField = fieldDef;
140  }
141 
142  // Verify the accessed field type matches the result type.
143  if (finalField.getType() != objectField.getResult().getType()) {
144  objectField.emitOpError("expected type ")
145  << objectField.getResult().getType()
146  << ", but accessed field has type " << finalField.getType();
147 
148  return WalkResult::interrupt();
149  }
150  return WalkResult::advance();
151  });
152  return LogicalResult::failure(result.wasInterrupted());
153  });
154  if (failed(result))
155  return signalPassFailure();
156  return markAllAnalysesPreserved();
157 }
158 
159 std::unique_ptr<mlir::Pass> circt::om::createVerifyObjectFieldsPass() {
160  return std::make_unique<VerifyObjectFieldsPass>();
161 }
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