CIRCT  19.0.0git
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 
22 using namespace circt;
23 using namespace circt::esi;
24 
25 AnyType AnyType::get(MLIRContext *context) { return Base::get(context); }
26 
27 LogicalResult
28 WindowType::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 
82 hw::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 
141 namespace mlir {
142 template <>
143 struct 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 
159 namespace llvm {
160 inline ::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 
167 ChannelBundleType 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 
177 void ESIDialect::registerTypes() {
178  addTypes<
179 #define GET_TYPEDEF_LIST
180 #include "circt/Dialect/ESI/ESITypes.cpp.inc"
181  >();
182 }
183 
184 mlir::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")
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:54
mlir::Type innerType(mlir::Type type)
Definition: ESITypes.cpp:184
Direction flip(Direction direction)
Flip a port direction.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
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