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"
26AnyType AnyType::get(MLIRContext *context) {
return Base::get(context); }
31 return llvm::make_filter_range(chan.getUses(), [](
auto &use) {
32 return !isa<SnoopValidReadyOp, SnoopTransactionOp>(use.getOwner());
35SmallVector<std::reference_wrapper<OpOperand>, 4>
36ChannelType::getConsumers(mlir::TypedValue<ChannelType> chan) {
37 return SmallVector<std::reference_wrapper<OpOperand>, 4>(
40bool ChannelType::hasOneConsumer(mlir::TypedValue<ChannelType> chan) {
42 if (consumers.empty())
44 return ++consumers.begin() == consumers.end();
46bool ChannelType::hasNoConsumers(mlir::TypedValue<ChannelType> chan) {
49OpOperand *ChannelType::getSingleConsumer(mlir::TypedValue<ChannelType> chan) {
51 auto iter = consumers.begin();
52 if (iter == consumers.end())
54 OpOperand *result = &*iter;
55 if (++iter != consumers.end())
59LogicalResult ChannelType::verifyChannel(mlir::TypedValue<ChannelType> chan) {
61 if (consumers.empty() || ++consumers.begin() == consumers.end())
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";
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);
76 return emitError() <<
"only windows into structs are currently supported";
78 auto fields = structInto.getElements();
79 for (
auto frame : frames) {
80 bool encounteredArrayOrListWithNumItems =
false;
83 DenseMap<StringAttr, WindowFieldType> frameFields;
84 for (
auto field : frame.getMembers())
89 while (!fields.empty() && !frameFields.empty()) {
90 hw::StructType::FieldInfo field = fields.front();
91 fields = fields.drop_front();
92 auto f = frameFields.find(field.name);
96 if (f == frameFields.end())
101 bool isArrayOrListWithNumItems =
102 hw::type_isa<hw::ArrayType, esi::ListType>(field.type) &&
103 f->getSecond().getNumItems() > 0;
104 if (isArrayOrListWithNumItems) {
105 if (encounteredArrayOrListWithNumItems)
107 <<
"cannot have two array or list fields with num items (in "
108 << field.name <<
")";
109 encounteredArrayOrListWithNumItems =
true;
113 uint64_t numItems = f->getSecond().getNumItems();
115 if (
auto arrField = hw::type_dyn_cast<hw::ArrayType>(field.type)) {
116 if (numItems > arrField.getNumElements())
118 <<
"num items is larger than array size in field "
120 }
else if (!hw::type_isa<esi::ListType>(field.type)) {
121 return emitError() <<
"specification of num items only allowed on "
122 "array or list fields (in "
123 << field.name <<
")";
126 frameFields.erase(f);
132 if (!frameFields.empty())
133 return emitError() <<
"invalid field name: "
134 << frameFields.begin()->getSecond().getFieldName();
139Type WindowType::getLoweredType()
const {
141 auto into = hw::type_cast<hw::StructType>(getInto());
143 for (hw::StructType::FieldInfo field : into.getElements())
144 intoFields[field.name] = field.type;
146 auto getInnerTypeOrSelf = [&](Type t) {
147 return TypeSwitch<Type, Type>(t)
148 .Case<hw::ArrayType>(
149 [](hw::ArrayType arr) {
return arr.getElementType(); })
150 .Case<esi::ListType>(
151 [](esi::ListType list) {
return list.getElementType(); })
152 .Default([&](Type t) {
return t; });
157 auto wrapInTypeAliasIfNeeded = [&](Type loweredType) -> Type {
158 if (
auto intoAlias = dyn_cast<hw::TypeAliasType>(getInto())) {
159 auto intoRef = intoAlias.getRef();
160 std::string aliasName = (Twine(intoRef.getLeafReference().getValue()) +
163 auto newRef = SymbolRefAttr::get(
164 intoRef.getRootReference(),
165 {FlatSymbolRefAttr::get(StringAttr::get(getContext(), aliasName))});
166 return hw::TypeAliasType::get(newRef, loweredType);
172 SmallVector<hw::UnionType::FieldInfo, 4> unionFields;
173 for (WindowFrameType frame : getFrames()) {
176 SmallVector<hw::StructType::FieldInfo, 4> fields;
177 SmallVector<hw::StructType::FieldInfo, 4> leftOverFields;
178 bool hasLeftOver =
false;
179 StringAttr leftOverName;
181 for (WindowFieldType field : frame.getMembers()) {
182 auto fieldTypeIter = intoFields.find(field.getFieldName());
183 assert(fieldTypeIter != intoFields.end());
184 auto fieldType = fieldTypeIter->getSecond();
187 if (field.getNumItems() == 0) {
190 auto type = getInnerTypeOrSelf(fieldType);
191 fields.push_back({field.getFieldName(), type});
192 leftOverFields.push_back({field.getFieldName(), type});
194 if (hw::type_isa<esi::ListType>(fieldType)) {
196 auto lastType = IntegerType::get(getContext(), 1);
197 auto lastField = StringAttr::get(getContext(),
"last");
198 fields.push_back({lastField, lastType});
199 leftOverFields.push_back({lastField, lastType});
203 hw::type_dyn_cast<hw::ArrayType>(fieldTypeIter->getSecond())) {
206 {field.getFieldName(), hw::ArrayType::get(array.getElementType(),
207 field.getNumItems())});
211 size_t leftOver = array.getNumElements() % field.getNumItems();
217 leftOverFields.push_back(
218 {field.getFieldName(),
219 hw::ArrayType::get(array.getElementType(), leftOver)});
221 leftOverName = StringAttr::get(
222 getContext(), Twine(frame.getName().getValue(),
"_leftOver"));
224 }
else if (
auto list = hw::type_cast<esi::ListType>(
225 fieldTypeIter->getSecond())) {
228 {field.getFieldName(),
229 hw::ArrayType::get(list.getElementType(), field.getNumItems())});
233 {StringAttr::get(getContext(),
234 Twine(field.getFieldName().getValue(),
"_size")),
235 IntegerType::get(getContext(),
236 llvm::Log2_64_Ceil(field.getNumItems()))});
238 fields.push_back({StringAttr::get(getContext(),
"last"),
239 IntegerType::get(getContext(), 1)});
241 llvm_unreachable(
"numItems specified on non-array/list field");
248 if (getFrames().size() == 1 && frame.getName().getValue().empty() &&
250 auto loweredStruct = hw::StructType::get(getContext(), fields);
251 return wrapInTypeAliasIfNeeded(loweredStruct);
255 unionFields.push_back(
256 {frame.getName(), hw::StructType::get(getContext(), fields), 0});
259 unionFields.push_back(
260 {leftOverName, hw::StructType::get(getContext(), leftOverFields), 0});
263 auto unionType = hw::UnionType::get(getContext(), unionFields);
264 return wrapInTypeAliasIfNeeded(unionType);
270 static FailureOr<::BundledChannel>
parse(AsmParser &p) {
273 if (p.parseType(type))
275 auto dir = FieldParser<::ChannelDirection>::parse(p);
278 if (p.parseKeywordOrString(&name))
280 return BundledChannel{StringAttr::get(p.getContext(), name), *dir, type};
286inline ::llvm::raw_ostream &
operator<<(::llvm::raw_ostream &p,
293ChannelBundleType ChannelBundleType::getReversed()
const {
294 SmallVector<BundledChannel, 4> reversed;
295 for (
auto channel : getChannels())
296 reversed.push_back({channel.name,
flip(channel.direction), channel.type});
297 return ChannelBundleType::get(getContext(), reversed, getResettable());
300#define GET_TYPEDEF_CLASSES
301#include "circt/Dialect/ESI/ESITypes.cpp.inc"
303void ESIDialect::registerTypes() {
305#define GET_TYPEDEF_LIST
306#include "circt/Dialect/ESI/ESITypes.cpp.inc"
311 circt::esi::ChannelType chan =
312 dyn_cast_or_null<circt::esi::ChannelType>(type);
314 type = chan.getInner();
assert(baseType &&"element must be base type")
static auto getChannelConsumers(mlir::TypedValue< ChannelType > chan)
Get the list of users with snoops filtered out.
static bool getFieldName(const FieldRef &fieldRef, SmallString< 32 > &string)
static Location getLoc(DefSlot slot)
mlir::Type innerType(mlir::Type type)
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
ModulePort::Direction flip(ModulePort::Direction direction)
Flip a port direction.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
inline ::llvm::raw_ostream & operator<<(::llvm::raw_ostream &p, ::BundledChannel channel)
ChannelDirection direction
static FailureOr<::BundledChannel > parse(AsmParser &p)