CIRCT 21.0.0git
Loading...
Searching...
No Matches
ESITypes.cpp
Go to the documentation of this file.
1//===- ESITypes.cpp - ESI types code defs -----------------------*- 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// Definitions for esi data types. Anything which doesn't have to be public
10// should go in here.
11//
12//===----------------------------------------------------------------------===//
13
17#include "mlir/IR/Attributes.h"
18#include "mlir/IR/DialectImplementation.h"
19#include "llvm/ADT/ArrayRef.h"
20#include "llvm/ADT/DenseMap.h"
21#include "llvm/ADT/TypeSwitch.h"
22
23using namespace circt;
24using namespace circt::esi;
25
26AnyType AnyType::get(MLIRContext *context) { return Base::get(context); }
27
28/// Get the list of users with snoops filtered out. Returns a filtered range
29/// which is lazily constructed.
30static auto getChannelConsumers(mlir::TypedValue<ChannelType> chan) {
31 return llvm::make_filter_range(chan.getUses(), [](auto &use) {
32 return !isa<SnoopValidReadyOp>(use.getOwner());
33 });
34}
35SmallVector<std::reference_wrapper<OpOperand>, 4>
36ChannelType::getConsumers(mlir::TypedValue<ChannelType> chan) {
37 return SmallVector<std::reference_wrapper<OpOperand>, 4>(
39}
40bool ChannelType::hasOneConsumer(mlir::TypedValue<ChannelType> chan) {
41 auto consumers = getChannelConsumers(chan);
42 if (consumers.empty())
43 return false;
44 return ++consumers.begin() == consumers.end();
45}
46bool ChannelType::hasNoConsumers(mlir::TypedValue<ChannelType> chan) {
47 return getChannelConsumers(chan).empty();
48}
49OpOperand *ChannelType::getSingleConsumer(mlir::TypedValue<ChannelType> chan) {
50 auto consumers = getChannelConsumers(chan);
51 auto iter = consumers.begin();
52 if (iter == consumers.end())
53 return nullptr;
54 OpOperand *result = &*iter;
55 if (++iter != consumers.end())
56 return nullptr;
57 return result;
58}
59LogicalResult ChannelType::verifyChannel(mlir::TypedValue<ChannelType> chan) {
60 auto consumers = getChannelConsumers(chan);
61 if (consumers.empty() || ++consumers.begin() == consumers.end())
62 return success();
63 auto err = chan.getDefiningOp()->emitOpError(
64 "channels must have at most one consumer");
65 for (auto &consumer : consumers)
66 err.attachNote(consumer.getOwner()->getLoc()) << "channel used here";
67 return err;
68}
69
70LogicalResult
71WindowType::verify(llvm::function_ref<InFlightDiagnostic()> emitError,
72 StringAttr name, Type into,
73 ArrayRef<WindowFrameType> frames) {
74 auto structInto = hw::type_dyn_cast<hw::StructType>(into);
75 if (!structInto)
76 return emitError() << "only windows into structs are currently supported";
77
78 auto fields = structInto.getElements();
79 for (auto frame : frames) {
80 // Efficiently look up fields in the frame.
81 DenseMap<StringAttr, WindowFieldType> frameFields;
82 for (auto field : frame.getMembers())
83 frameFields[field.getFieldName()] = field;
84
85 // Iterate through the list of struct fields until we've encountered all the
86 // fields listed in the frame.
87 while (!fields.empty() && !frameFields.empty()) {
88 hw::StructType::FieldInfo field = fields.front();
89 fields = fields.drop_front();
90 auto f = frameFields.find(field.name);
91
92 // If a field in the struct isn't listed, it's being omitted from the
93 // window so we just skip it.
94 if (f == frameFields.end())
95 continue;
96
97 // If 'numItems' is specified, gotta run more checks.
98 uint64_t numItems = f->getSecond().getNumItems();
99 if (numItems > 0) {
100 auto arrField = hw::type_dyn_cast<hw::ArrayType>(field.type);
101 if (!arrField)
102 return emitError() << "cannot specify num items on non-array field "
103 << field.name;
104 if (numItems > arrField.getNumElements())
105 return emitError() << "num items is larger than array size in field "
106 << field.name;
107 if (frame.getMembers().size() != 1)
108 return emitError()
109 << "array with size specified must be in their own frame (in "
110 << field.name << ")";
111 }
112 frameFields.erase(f);
113 }
114
115 // If there is anything left in the frame list, it either refers to a
116 // non-existant field or said frame was already consumed by a previous
117 // frame.
118 if (!frameFields.empty())
119 return emitError() << "invalid field name: "
120 << frameFields.begin()->getSecond().getFieldName();
121 }
122 return success();
123}
124
125hw::UnionType WindowType::getLoweredType() const {
126 // Assemble a fast lookup of struct fields to types.
127 auto into = hw::type_cast<hw::StructType>(getInto());
129 for (hw::StructType::FieldInfo field : into.getElements())
130 intoFields[field.name] = field.type;
131
132 // Build the union, frame by frame
133 SmallVector<hw::UnionType::FieldInfo, 4> unionFields;
134 for (WindowFrameType frame : getFrames()) {
135
136 // ... field by field.
137 SmallVector<hw::StructType::FieldInfo, 4> fields;
138 for (WindowFieldType field : frame.getMembers()) {
139 auto fieldTypeIter = intoFields.find(field.getFieldName());
140 assert(fieldTypeIter != intoFields.end());
141
142 // If the number of items isn't specified, just use the type.
143 if (field.getNumItems() == 0) {
144 fields.push_back({field.getFieldName(), fieldTypeIter->getSecond()});
145 } else {
146 // If the number of items is specified, we can assume that it's an array
147 // type.
148 auto array = hw::type_cast<hw::ArrayType>(fieldTypeIter->getSecond());
149 assert(fields.empty()); // Checked by the validator.
150
151 // The first union entry should be an array of length numItems.
152 fields.push_back(
153 {field.getFieldName(),
154 hw::ArrayType::get(array.getElementType(), field.getNumItems())});
155 unionFields.push_back(
156 {frame.getName(), hw::StructType::get(getContext(), fields), 0});
157 fields.clear();
158
159 // If the array size is not a multiple of numItems, we need another
160 // frame for the left overs.
161 size_t leftOver = array.getNumElements() % field.getNumItems();
162 if (leftOver) {
163 fields.push_back(
164 {field.getFieldName(),
165 hw::ArrayType::get(array.getElementType(), leftOver)});
166
167 unionFields.push_back(
168 {StringAttr::get(getContext(),
169 Twine(frame.getName().getValue(), "_leftOver")),
170 hw::StructType::get(getContext(), fields), 0});
171 fields.clear();
172 }
173 }
174 }
175
176 if (!fields.empty())
177 unionFields.push_back(
178 {frame.getName(), hw::StructType::get(getContext(), fields), 0});
179 }
180
181 return hw::UnionType::get(getContext(), unionFields);
182}
183
184namespace mlir {
185template <>
186struct FieldParser<::BundledChannel, ::BundledChannel> {
187 static FailureOr<::BundledChannel> parse(AsmParser &p) {
188 ChannelType type;
189 std::string name;
190 if (p.parseType(type))
191 return failure();
192 auto dir = FieldParser<::ChannelDirection>::parse(p);
193 if (failed(dir))
194 return failure();
195 if (p.parseKeywordOrString(&name))
196 return failure();
197 return BundledChannel{StringAttr::get(p.getContext(), name), *dir, type};
198 }
199};
200} // namespace mlir
201
202namespace llvm {
203inline ::llvm::raw_ostream &operator<<(::llvm::raw_ostream &p,
204 ::BundledChannel channel) {
205 p << channel.type << " " << channel.direction << " " << channel.name;
206 return p;
207}
208} // namespace llvm
209
210ChannelBundleType ChannelBundleType::getReversed() const {
211 SmallVector<BundledChannel, 4> reversed;
212 for (auto channel : getChannels())
213 reversed.push_back({channel.name, flip(channel.direction), channel.type});
214 return ChannelBundleType::get(getContext(), reversed, getResettable());
215}
216
217#define GET_TYPEDEF_CLASSES
218#include "circt/Dialect/ESI/ESITypes.cpp.inc"
219
220void ESIDialect::registerTypes() {
221 addTypes<
222#define GET_TYPEDEF_LIST
223#include "circt/Dialect/ESI/ESITypes.cpp.inc"
224 >();
225}
226
227mlir::Type circt::esi::innerType(mlir::Type type) {
228 circt::esi::ChannelType chan =
229 dyn_cast_or_null<circt::esi::ChannelType>(type);
230 if (chan) // Unwrap the channel if it's a channel.
231 type = chan.getInner();
232
233 return type;
234}
assert(baseType &&"element must be base type")
static auto getChannelConsumers(mlir::TypedValue< ChannelType > chan)
Get the list of users with snoops filtered out.
Definition ESITypes.cpp:30
static bool getFieldName(const FieldRef &fieldRef, SmallString< 32 > &string)
mlir::Type innerType(mlir::Type type)
Definition ESITypes.cpp:227
ModulePort::Direction flip(ModulePort::Direction direction)
Flip a port direction.
Definition HWOps.cpp:36
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
inline ::llvm::raw_ostream & operator<<(::llvm::raw_ostream &p, ::BundledChannel channel)
Definition ESITypes.cpp:203
ChannelDirection direction
Definition ESITypes.h:38
static FailureOr<::BundledChannel > parse(AsmParser &p)
Definition ESITypes.cpp:187