CIRCT  20.0.0git
FIRRTLInstanceImplementation.cpp
Go to the documentation of this file.
1 //===- FIRRTLInstanceImplementation.cpp - Utilities for instance-like ops -===//
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 
11 
12 using namespace circt;
13 using namespace circt::firrtl;
14 
15 LogicalResult
17  SymbolTableCollection &symbolTable,
18  mlir::FlatSymbolRefAttr moduleName) {
19  auto referencedModule =
20  symbolTable.lookupNearestSymbolFrom<FModuleLike>(instanceOp, moduleName);
21  if (!referencedModule) {
22  return instanceOp->emitOpError("invalid symbol reference");
23  }
24 
25  // Check this is not a class.
26  if (isa<ClassOp /* ClassLike */>(referencedModule))
27  return instanceOp->emitOpError("must instantiate a module not a class")
28  .attachNote(referencedModule.getLoc())
29  << "class declared here";
30 
31  // Small helper add a note to the original declaration.
32  auto emitNote = [&](InFlightDiagnostic &&diag) -> InFlightDiagnostic && {
33  diag.attachNote(referencedModule->getLoc())
34  << "original module declared here";
35  return std::move(diag);
36  };
37 
38  // Check that all the attribute arrays are the right length up front. This
39  // lets us safely use the port name in error messages below.
40  size_t numResults = instanceOp->getNumResults();
41  size_t numExpected = referencedModule.getNumPorts();
42  if (numResults != numExpected) {
43  return emitNote(instanceOp->emitOpError()
44  << "has a wrong number of results; expected " << numExpected
45  << " but got " << numResults);
46  }
47  auto portDirections =
48  instanceOp->getAttrOfType<mlir::DenseBoolArrayAttr>("portDirections");
49  if (static_cast<size_t>(portDirections.size()) != numExpected)
50  return emitNote(
51  instanceOp->emitOpError("the number of port directions should be "
52  "equal to the number of results"));
53 
54  auto portNames = instanceOp->getAttrOfType<ArrayAttr>("portNames");
55  if (portNames.size() != numExpected)
56  return emitNote(
57  instanceOp->emitOpError("the number of port names should be "
58  "equal to the number of results"));
59 
60  auto portAnnotations =
61  instanceOp->getAttrOfType<ArrayAttr>("portAnnotations");
62  if (portAnnotations.size() != numExpected)
63  return emitNote(
64  instanceOp->emitOpError("the number of result annotations should be "
65  "equal to the number of results"));
66 
67  // Check that the port names match the referenced module.
68  if (portNames != referencedModule.getPortNamesAttr()) {
69  // We know there is an error, try to figure out whats wrong.
70  auto moduleNames = referencedModule.getPortNamesAttr();
71  // First compare the sizes:
72  if (portNames.size() != moduleNames.size()) {
73  return emitNote(instanceOp->emitOpError()
74  << "has a wrong number of directions; expected "
75  << moduleNames.size() << " but got " << portNames.size());
76  }
77  // Next check the values:
78  for (size_t i = 0; i != numResults; ++i) {
79  if (portNames[i] != moduleNames[i]) {
80  return emitNote(instanceOp->emitOpError()
81  << "name for port " << i << " must be "
82  << moduleNames[i] << ", but got " << portNames[i]);
83  }
84  }
85  llvm_unreachable("should have found something wrong");
86  }
87 
88  // Check that the types match.
89  for (size_t i = 0; i != numResults; i++) {
90  auto resultType = instanceOp->getResult(i).getType();
91  auto expectedType = referencedModule.getPortType(i);
92  if (resultType != expectedType) {
93  return emitNote(instanceOp->emitOpError()
94  << "result type for " << portNames[i] << " must be "
95  << expectedType << ", but got " << resultType);
96  }
97  }
98 
99  // Check that the port directions are consistent with the referenced module's.
100  if (portDirections != referencedModule.getPortDirectionsAttr()) {
101  // We know there is an error, try to figure out whats wrong.
102  auto moduleDirectionAttr = referencedModule.getPortDirectionsAttr();
103  // First compare the sizes:
104  auto expectedWidth = moduleDirectionAttr.size();
105  auto actualWidth = portDirections.size();
106  if (expectedWidth != actualWidth) {
107  return emitNote(instanceOp->emitOpError()
108  << "has a wrong number of directions; expected "
109  << expectedWidth << " but got " << actualWidth);
110  }
111  // Next check the values.
112  auto instanceDirs = portDirections;
113  for (size_t i = 0; i != numResults; ++i) {
114  if (instanceDirs[i] != moduleDirectionAttr[i]) {
115  return emitNote(instanceOp->emitOpError()
116  << "direction for " << portNames[i] << " must be \""
117  << direction::toString(moduleDirectionAttr[i])
118  << "\", but got \""
119  << direction::toString(instanceDirs[i]) << "\"");
120  }
121  }
122  llvm_unreachable("should have found something wrong");
123  }
124 
125  // Check that the instance op lists the correct layer requirements.
126  auto instanceLayers = instanceOp->getAttrOfType<ArrayAttr>("layers");
127  auto moduleLayers = referencedModule.getLayersAttr();
128  if (instanceLayers != moduleLayers)
129  return emitNote(instanceOp->emitOpError()
130  << "layers must be " << moduleLayers << ", but got "
131  << instanceLayers);
132 
133  return success();
134 }
static StringRef toString(Direction direction)
LogicalResult verifyReferencedModule(Operation *instanceOp, SymbolTableCollection &symbolTable, mlir::FlatSymbolRefAttr moduleName)
Verify that the instance refers to a valid FIRRTL module.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21