CIRCT 22.0.0git
Loading...
Searching...
No Matches
HWOpInterfaces.cpp
Go to the documentation of this file.
1//===- HWOpInterfaces.cpp - Implement the HW op interfaces ----------------===//
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// This file implement the HW operation interfaces.
10//
11//===----------------------------------------------------------------------===//
12
16#include "circt/Support/LLVM.h"
17#include "mlir/IR/BuiltinAttributes.h"
18#include "mlir/IR/BuiltinTypes.h"
19#include "llvm/ADT/SmallBitVector.h"
20#include "llvm/ADT/SmallPtrSet.h"
21#include "llvm/ADT/StringRef.h"
22
23using namespace circt;
24
25hw::InnerSymAttr hw::PortInfo::getSym() const {
26 if (attrs)
27 return attrs.getAs<::circt::hw::InnerSymAttr>(
28 hw::HWModuleLike::getPortSymbolAttrName());
29 return {};
30}
31
32void hw::PortInfo::setSym(InnerSymAttr sym, MLIRContext *ctx) {
33 auto portSymAttr =
34 StringAttr::get(ctx, hw::HWModuleLike::getPortSymbolAttrName());
35 NamedAttrList pattr(attrs);
36 Attribute oldValue;
37 if (!sym)
38 oldValue = pattr.erase(portSymAttr);
39 else
40 oldValue = pattr.set(portSymAttr, sym);
41 if (oldValue != sym) {
42 attrs = pattr.getDictionary(ctx);
43 }
44}
45
47 if (attrs)
48 if (auto updatedName = attrs.get("hw.verilogName"))
49 return cast<StringAttr>(updatedName).getValue();
50 return name.getValue();
51}
52
53LogicalResult
54hw::verifyInnerSymAttr(InnerSymAttr innerSym, Type type,
55 llvm::function_ref<InFlightDiagnostic()> emitError) {
56 assert(innerSym && "null inner symbol attribute provided");
57 // Tentatively accept empty inner symbol attributes.
58 // In the future we may prefer these over NULL.
59 if (innerSym.empty())
60 return success();
61
62 if (!type) {
63 // No "type" provided means must have zero or one inner symbols.
64 // If symbol is present, must have fieldID == 0.
65 // Scan and reject any with fieldID != 0.
66 for (auto prop : innerSym) {
67 if (prop.getFieldID() != 0)
68 return emitError() << "does not support per-field inner symbols, but "
69 "has inner symbol '"
70 << prop.getName().getValue()
71 << "' with non-zero field id " << prop.getFieldID();
72 }
73 // If scan passed but there are multiple inner symbols for this target.
74 if (innerSym.size() > 1) {
75 // Multiple with fieldID == 0.
76 auto err = emitError() << "has more than one symbol defined: ";
77 llvm::interleaveComma(innerSym, err, [&](auto prop) {
78 err << "'" << prop.getName().getValue() << "'";
79 });
80 return err;
81 }
82 return success();
83 }
84
85 auto maxFields = FieldIdImpl::getMaxFieldID(type);
86 llvm::SmallBitVector indices(maxFields + 1);
87 llvm::SmallPtrSet<Attribute, 8> symNames;
88 // Ensure fieldID and symbol names are unique.
89 auto uniqSyms = [&](InnerSymPropertiesAttr p) {
90 if (maxFields < p.getFieldID()) {
91 emitError() << "field id " << p.getFieldID()
92 << " is greater than the maximum field id " << maxFields;
93 return false;
94 }
95 if (indices.test(p.getFieldID())) {
96 emitError() << "cannot assign multiple symbol names to the field id "
97 << p.getFieldID();
98 return false;
99 }
100 indices.set(p.getFieldID());
101 auto it = symNames.insert(p.getName());
102 if (!it.second) {
103 emitError() << "cannot reuse symbol name '" << p.getName().getValue()
104 << "'";
105 return false;
106 }
107 return true;
108 };
109
110 if (!llvm::all_of(innerSym.getProps(), uniqSyms))
111 return failure();
112
113 return success();
114}
115
116LogicalResult hw::verifyInnerSymOp(InnerSymbolOpInterface op) {
117 auto innerSym = op.getInnerSymAttr();
118 // If does not have any inner sym then ignore.
119 if (!innerSym)
120 return success();
121
122 if (innerSym.empty())
123 return op->emitOpError("has empty list of inner symbols");
124
125 if (!op.supportsPerFieldSymbols())
126 return verifyInnerSymAttr(innerSym, [op]() { return op->emitOpError(); });
127
128 // If op supports per-field symbols, but does not have a target result,
129 // its up to the operation to verify itself.
130 // (there are no uses for this presently, but be open to this anyway.)
131 auto result = op.getTargetResult();
132 if (!result)
133 return success();
134
135 return verifyInnerSymAttr(innerSym, result.getType(),
136 [op]() { return op->emitOpError(); });
137}
138
139LogicalResult hw::verifyPortInnerSymsIfPortList(Operation *op) {
140 assert(op->hasTrait<OpTrait::InnerSymbolTable>());
141 PortList opWithPorts = dyn_cast<hw::PortList>(op);
142 // Skip if not a PortList.
143 if (!opWithPorts)
144 return success();
145
146 auto ports = opWithPorts.getPortList();
147 for (auto const &indexAndPort : llvm::enumerate(ports)) {
148 auto &pi = indexAndPort.value();
149 auto idx = indexAndPort.index();
150 Location loc = pi.loc ? Location(pi.loc) : opWithPorts.getLoc();
151 if (auto sym = pi.getSym())
152 if (failed(hw::verifyInnerSymAttr(sym, pi.type, [&]() {
153 return mlir::emitError(loc)
154 << "verification of inner symbol"
155 << (sym.size() > 1 ? "s" : "") << " failed on port " << idx
156 << " with name " << pi.name << ": ";
157 })))
158 return failure();
159 }
160
161 return success();
162}
163
164raw_ostream &circt::hw::operator<<(raw_ostream &printer, PortInfo port) {
165 StringRef dirstr;
166 switch (port.dir) {
167 case ModulePort::Direction::Input:
168 dirstr = "input";
169 break;
170 case ModulePort::Direction::Output:
171 dirstr = "output";
172 break;
173 case ModulePort::Direction::InOut:
174 dirstr = "inout";
175 break;
176 }
177 printer << dirstr << " " << port.name << " : " << port.type << " (argnum "
178 << port.argNum << ", sym " << port.getSym() << ", loc " << port.loc
179 << ", args " << port.attrs << ")";
180 return printer;
181}
182
183#include "circt/Dialect/HW/HWOpInterfaces.cpp.inc"
assert(baseType &&"element must be base type")
A trait for inner symbol table functionality on an operation.
OS & operator<<(OS &os, const InnerSymTarget &target)
Printing InnerSymTarget's.
LogicalResult verifyInnerSymAttr(InnerSymAttr innerSym, Type type, llvm::function_ref< InFlightDiagnostic()> emitError)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
mlir::Type type
Definition HWTypes.h:31
mlir::StringAttr name
Definition HWTypes.h:30
This holds the name, type, direction of a module's ports.
StringRef getVerilogName() const
DictionaryAttr attrs
The optional symbol for this port.
size_t argNum
This is the argument index or the result index depending on the direction.
void setSym(InnerSymAttr sym, MLIRContext *ctx)
InnerSymAttr getSym() const