CIRCT 20.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
16#include "mlir/IR/Attributes.h"
17#include "mlir/IR/DialectImplementation.h"
18#include "llvm/ADT/ArrayRef.h"
19#include "llvm/ADT/DenseMap.h"
20#include "llvm/ADT/TypeSwitch.h"
21
22using namespace circt;
23using namespace circt::esi;
24
25AnyType AnyType::get(MLIRContext *context) { return Base::get(context); }
26
27LogicalResult
28WindowType::verify(llvm::function_ref<InFlightDiagnostic()> emitError,
29 StringAttr name, Type into,
30 ArrayRef<WindowFrameType> frames) {
31 auto structInto = hw::type_dyn_cast<hw::StructType>(into);
32 if (!structInto)
33 return emitError() << "only windows into structs are currently supported";
34
35 auto fields = structInto.getElements();
36 for (auto frame : frames) {
37 // Efficiently look up fields in the frame.
38 DenseMap<StringAttr, WindowFieldType> frameFields;
39 for (auto field : frame.getMembers())
40 frameFields[field.getFieldName()] = field;
41
42 // Iterate through the list of struct fields until we've encountered all the
43 // fields listed in the frame.
44 while (!fields.empty() && !frameFields.empty()) {
45 hw::StructType::FieldInfo field = fields.front();
46 fields = fields.drop_front();
47 auto f = frameFields.find(field.name);
48
49 // If a field in the struct isn't listed, it's being omitted from the
50 // window so we just skip it.
51 if (f == frameFields.end())
52 continue;
53
54 // If 'numItems' is specified, gotta run more checks.
55 uint64_t numItems = f->getSecond().getNumItems();
56 if (numItems > 0) {
57 auto arrField = hw::type_dyn_cast<hw::ArrayType>(field.type);
58 if (!arrField)
59 return emitError() << "cannot specify num items on non-array field "
60 << field.name;
61 if (numItems > arrField.getNumElements())
62 return emitError() << "num items is larger than array size in field "
63 << field.name;
64 if (frame.getMembers().size() != 1)
65 return emitError()
66 << "array with size specified must be in their own frame (in "
67 << field.name << ")";
68 }
69 frameFields.erase(f);
70 }
71
72 // If there is anything left in the frame list, it either refers to a
73 // non-existant field or said frame was already consumed by a previous
74 // frame.
75 if (!frameFields.empty())
76 return emitError() << "invalid field name: "
77 << frameFields.begin()->getSecond().getFieldName();
78 }
79 return success();
80}
81
82hw::UnionType WindowType::getLoweredType() const {
83 // Assemble a fast lookup of struct fields to types.
84 auto into = hw::type_cast<hw::StructType>(getInto());
86 for (hw::StructType::FieldInfo field : into.getElements())
87 intoFields[field.name] = field.type;
88
89 // Build the union, frame by frame
90 SmallVector<hw::UnionType::FieldInfo, 4> unionFields;
91 for (WindowFrameType frame : getFrames()) {
92
93 // ... field by field.
94 SmallVector<hw::StructType::FieldInfo, 4> fields;
95 for (WindowFieldType field : frame.getMembers()) {
96 auto fieldTypeIter = intoFields.find(field.getFieldName());
97 assert(fieldTypeIter != intoFields.end());
98
99 // If the number of items isn't specified, just use the type.
100 if (field.getNumItems() == 0) {
101 fields.push_back({field.getFieldName(), fieldTypeIter->getSecond()});
102 } else {
103 // If the number of items is specified, we can assume that it's an array
104 // type.
105 auto array = hw::type_cast<hw::ArrayType>(fieldTypeIter->getSecond());
106 assert(fields.empty()); // Checked by the validator.
107
108 // The first union entry should be an array of length numItems.
109 fields.push_back(
110 {field.getFieldName(),
111 hw::ArrayType::get(array.getElementType(), field.getNumItems())});
112 unionFields.push_back(
113 {frame.getName(), hw::StructType::get(getContext(), fields), 0});
114 fields.clear();
115
116 // If the array size is not a multiple of numItems, we need another
117 // frame for the left overs.
118 size_t leftOver = array.getNumElements() % field.getNumItems();
119 if (leftOver) {
120 fields.push_back(
121 {field.getFieldName(),
122 hw::ArrayType::get(array.getElementType(), leftOver)});
123
124 unionFields.push_back(
125 {StringAttr::get(getContext(),
126 Twine(frame.getName().getValue(), "_leftOver")),
127 hw::StructType::get(getContext(), fields), 0});
128 fields.clear();
129 }
130 }
131 }
132
133 if (!fields.empty())
134 unionFields.push_back(
135 {frame.getName(), hw::StructType::get(getContext(), fields), 0});
136 }
137
138 return hw::UnionType::get(getContext(), unionFields);
139}
140
141namespace mlir {
142template <>
143struct FieldParser<::BundledChannel, ::BundledChannel> {
144 static FailureOr<::BundledChannel> parse(AsmParser &p) {
145 ChannelType type;
146 std::string name;
147 if (p.parseType(type))
148 return failure();
149 auto dir = FieldParser<::ChannelDirection>::parse(p);
150 if (failed(dir))
151 return failure();
152 if (p.parseKeywordOrString(&name))
153 return failure();
154 return BundledChannel{StringAttr::get(p.getContext(), name), *dir, type};
155 }
156};
157} // namespace mlir
158
159namespace llvm {
160inline ::llvm::raw_ostream &operator<<(::llvm::raw_ostream &p,
161 ::BundledChannel channel) {
162 p << channel.type << " " << channel.direction << " " << channel.name;
163 return p;
164}
165} // namespace llvm
166
167ChannelBundleType ChannelBundleType::getReversed() const {
168 SmallVector<BundledChannel, 4> reversed;
169 for (auto channel : getChannels())
170 reversed.push_back({channel.name, flip(channel.direction), channel.type});
171 return ChannelBundleType::get(getContext(), reversed, getResettable());
172}
173
174#define GET_TYPEDEF_CLASSES
175#include "circt/Dialect/ESI/ESITypes.cpp.inc"
176
177void ESIDialect::registerTypes() {
178 addTypes<
179#define GET_TYPEDEF_LIST
180#include "circt/Dialect/ESI/ESITypes.cpp.inc"
181 >();
182}
183
184mlir::Type circt::esi::innerType(mlir::Type type) {
185 circt::esi::ChannelType chan =
186 dyn_cast_or_null<circt::esi::ChannelType>(type);
187 if (chan) // Unwrap the channel if it's a channel.
188 type = chan.getInner();
189
190 return type;
191}
assert(baseType &&"element must be base type")
static bool getFieldName(const FieldRef &fieldRef, SmallString< 32 > &string)
mlir::Type innerType(mlir::Type type)
Definition ESITypes.cpp:184
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:160
ChannelDirection direction
Definition ESITypes.h:38
static FailureOr<::BundledChannel > parse(AsmParser &p)
Definition ESITypes.cpp:144