CIRCT 20.0.0git
Loading...
Searching...
No Matches
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
12using namespace circt;
13using namespace circt::firrtl;
14
15LogicalResult
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.