CIRCT  20.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  // 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 
139 std::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: DebugAnalysis.h:21
Definition: om.py:1