CIRCT  19.0.0git
ESIOps.cpp
Go to the documentation of this file.
1 //===- ESIOps.cpp - ESI op 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 // This is where op definitions live.
10 //
11 //===----------------------------------------------------------------------===//
12 
16 #include "circt/Dialect/SV/SVOps.h"
18 #include "circt/Support/LLVM.h"
19 
20 #include "mlir/IR/Builders.h"
21 #include "mlir/IR/BuiltinTypes.h"
22 #include "mlir/IR/PatternMatch.h"
23 #include "mlir/IR/SymbolTable.h"
24 
25 using namespace circt;
26 using namespace circt::esi;
27 
28 //===----------------------------------------------------------------------===//
29 // ChannelBufferOp functions.
30 //===----------------------------------------------------------------------===//
31 
32 ParseResult ChannelBufferOp::parse(OpAsmParser &parser,
33  OperationState &result) {
34  llvm::SMLoc inputOperandsLoc = parser.getCurrentLocation();
35 
36  llvm::SmallVector<OpAsmParser::UnresolvedOperand, 4> operands;
37  if (parser.parseOperandList(operands, /*requiredOperandCount=*/3,
38  /*delimiter=*/OpAsmParser::Delimiter::None))
39  return failure();
40 
41  Type innerOutputType;
42  if (parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
43  parser.parseType(innerOutputType))
44  return failure();
45  auto outputType =
46  ChannelType::get(parser.getBuilder().getContext(), innerOutputType);
47  result.addTypes({outputType});
48 
49  auto clkTy = seq::ClockType::get(result.getContext());
50  auto i1 = IntegerType::get(result.getContext(), 1);
51  if (parser.resolveOperands(operands, {clkTy, i1, outputType},
52  inputOperandsLoc, result.operands))
53  return failure();
54  return success();
55 }
56 
57 void ChannelBufferOp::print(OpAsmPrinter &p) {
58  p << " " << getClk() << ", " << getRst() << ", " << getInput();
59  p.printOptionalAttrDict((*this)->getAttrs());
60  p << " : " << innerType();
61 }
62 
63 circt::esi::ChannelType ChannelBufferOp::channelType() {
64  return cast<circt::esi::ChannelType>(getInput().getType());
65 }
66 
67 LogicalResult ChannelBufferOp::verify() {
68  if (getInput().getType().getSignaling() != ChannelSignaling::ValidReady)
69  return emitOpError("currently only supports valid-ready signaling");
70  if (getOutput().getType().getDataDelay() != 0)
71  return emitOpError("currently only supports channels with zero data delay");
72  return success();
73 }
74 
75 //===----------------------------------------------------------------------===//
76 // PipelineStageOp functions.
77 //===----------------------------------------------------------------------===//
78 
79 ParseResult PipelineStageOp::parse(OpAsmParser &parser,
80  OperationState &result) {
81  llvm::SMLoc inputOperandsLoc = parser.getCurrentLocation();
82 
83  SmallVector<OpAsmParser::UnresolvedOperand, 4> operands;
84  Type innerOutputType;
85  if (parser.parseOperandList(operands, /*requiredOperandCount=*/3) ||
86  parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
87  parser.parseType(innerOutputType))
88  return failure();
89  auto type =
90  ChannelType::get(parser.getBuilder().getContext(), innerOutputType);
91  result.addTypes({type});
92 
93  auto clkTy = seq::ClockType::get(result.getContext());
94  auto i1 = IntegerType::get(result.getContext(), 1);
95  if (parser.resolveOperands(operands, {clkTy, i1, type}, inputOperandsLoc,
96  result.operands))
97  return failure();
98  return success();
99 }
100 
101 void PipelineStageOp::print(OpAsmPrinter &p) {
102  p << " " << getClk() << ", " << getRst() << ", " << getInput();
103  p.printOptionalAttrDict((*this)->getAttrs());
104  p << " : " << innerType();
105 }
106 
107 circt::esi::ChannelType PipelineStageOp::channelType() {
108  return cast<circt::esi::ChannelType>(getInput().getType());
109 }
110 
111 //===----------------------------------------------------------------------===//
112 // Wrap / unwrap.
113 //===----------------------------------------------------------------------===//
114 
115 ParseResult WrapValidReadyOp::parse(OpAsmParser &parser,
116  OperationState &result) {
117  llvm::SMLoc inputOperandsLoc = parser.getCurrentLocation();
118 
119  llvm::SmallVector<OpAsmParser::UnresolvedOperand, 2> opList;
120  Type innerOutputType;
121  if (parser.parseOperandList(opList, 2, OpAsmParser::Delimiter::None) ||
122  parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
123  parser.parseType(innerOutputType))
124  return failure();
125 
126  auto boolType = parser.getBuilder().getI1Type();
127  auto outputType =
128  ChannelType::get(parser.getBuilder().getContext(), innerOutputType);
129  result.addTypes({outputType, boolType});
130  if (parser.resolveOperands(opList, {innerOutputType, boolType},
131  inputOperandsLoc, result.operands))
132  return failure();
133  return success();
134 }
135 
136 void WrapValidReadyOp::print(OpAsmPrinter &p) {
137  p << " " << getRawInput() << ", " << getValid();
138  p.printOptionalAttrDict((*this)->getAttrs());
139  p << " : " << innerType();
140 }
141 
142 void WrapValidReadyOp::build(OpBuilder &b, OperationState &state, Value data,
143  Value valid) {
144  build(b, state, ChannelType::get(state.getContext(), data.getType()),
145  b.getI1Type(), data, valid);
146 }
147 
148 LogicalResult WrapValidReadyOp::verify() {
149  if (getChanOutput().getType().getSignaling() != ChannelSignaling::ValidReady)
150  return emitOpError("only supports valid-ready signaling");
151  return success();
152 }
153 
154 ParseResult UnwrapValidReadyOp::parse(OpAsmParser &parser,
155  OperationState &result) {
156  llvm::SMLoc inputOperandsLoc = parser.getCurrentLocation();
157 
158  llvm::SmallVector<OpAsmParser::UnresolvedOperand, 2> opList;
159  Type outputType;
160  if (parser.parseOperandList(opList, 2, OpAsmParser::Delimiter::None) ||
161  parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
162  parser.parseType(outputType))
163  return failure();
164 
165  auto inputType =
166  ChannelType::get(parser.getBuilder().getContext(), outputType);
167 
168  auto boolType = parser.getBuilder().getI1Type();
169 
170  result.addTypes({inputType.getInner(), boolType});
171  if (parser.resolveOperands(opList, {inputType, boolType}, inputOperandsLoc,
172  result.operands))
173  return failure();
174  return success();
175 }
176 
177 void UnwrapValidReadyOp::print(OpAsmPrinter &p) {
178  p << " " << getChanInput() << ", " << getReady();
179  p.printOptionalAttrDict((*this)->getAttrs());
180  p << " : " << getRawOutput().getType();
181 }
182 
183 LogicalResult UnwrapValidReadyOp::verify() {
184  if (getChanInput().getType().getSignaling() != ChannelSignaling::ValidReady)
185  return emitOpError("only supports valid-ready signaling");
186  return success();
187 }
188 
189 circt::esi::ChannelType WrapValidReadyOp::channelType() {
190  return cast<circt::esi::ChannelType>(getChanOutput().getType());
191 }
192 
193 void UnwrapValidReadyOp::build(OpBuilder &b, OperationState &state,
194  Value inChan, Value ready) {
195  auto inChanType = cast<ChannelType>(inChan.getType());
196  build(b, state, inChanType.getInner(), b.getI1Type(), inChan, ready);
197 }
198 
199 circt::esi::ChannelType UnwrapValidReadyOp::channelType() {
200  return cast<circt::esi::ChannelType>(getChanInput().getType());
201 }
202 
203 circt::esi::ChannelType WrapFIFOOp::channelType() {
204  return cast<circt::esi::ChannelType>(getChanOutput().getType());
205 }
206 
207 ParseResult parseWrapFIFOType(OpAsmParser &p, Type &dataType,
208  Type &chanInputType) {
209  auto loc = p.getCurrentLocation();
210  ChannelType chType;
211  if (p.parseType(chType))
212  return failure();
213  if (chType.getSignaling() != ChannelSignaling::FIFO)
214  return p.emitError(loc, "can only wrap into FIFO type");
215  dataType = chType.getInner();
216  chanInputType = chType;
217  return success();
218 }
219 
220 void printWrapFIFOType(OpAsmPrinter &p, WrapFIFOOp wrap, Type dataType,
221  Type chanType) {
222  p << chanType;
223 }
224 
225 LogicalResult WrapFIFOOp::verify() {
226  if (getChanOutput().getType().getSignaling() != ChannelSignaling::FIFO)
227  return emitOpError("only supports FIFO signaling");
228  return success();
229 }
230 
231 circt::esi::ChannelType UnwrapFIFOOp::channelType() {
232  return cast<circt::esi::ChannelType>(getChanInput().getType());
233 }
234 
235 LogicalResult UnwrapFIFOOp::verify() {
236  if (getChanInput().getType().getSignaling() != ChannelSignaling::FIFO)
237  return emitOpError("only supports FIFO signaling");
238  return success();
239 }
240 
241 LogicalResult
242 UnwrapFIFOOp::inferReturnTypes(MLIRContext *context, std::optional<Location>,
243  ValueRange operands, DictionaryAttr,
244  mlir::OpaqueProperties, mlir::RegionRange,
245  SmallVectorImpl<Type> &inferredResulTypes) {
246  inferredResulTypes.push_back(
247  cast<ChannelType>(operands[0].getType()).getInner());
248  inferredResulTypes.push_back(
249  IntegerType::get(context, 1, IntegerType::Signless));
250  return success();
251 }
252 
253 /// If 'iface' looks like an ESI interface, return the inner data type.
254 static Type getEsiDataType(circt::sv::InterfaceOp iface) {
255  using namespace circt::sv;
256  if (!iface.lookupSymbol<InterfaceSignalOp>("valid"))
257  return Type();
258  if (!iface.lookupSymbol<InterfaceSignalOp>("ready"))
259  return Type();
260  auto dataSig = iface.lookupSymbol<InterfaceSignalOp>("data");
261  if (!dataSig)
262  return Type();
263  return dataSig.getType();
264 }
265 
266 /// Verify that the modport type of 'modportArg' points to an interface which
267 /// looks like an ESI interface and the inner data from said interface matches
268 /// the chan type's inner data type.
269 static LogicalResult verifySVInterface(Operation *op,
270  circt::sv::ModportType modportType,
271  ChannelType chanType) {
272  auto modport =
273  SymbolTable::lookupNearestSymbolFrom<circt::sv::InterfaceModportOp>(
274  op, modportType.getModport());
275  if (!modport)
276  return op->emitError("Could not find modport ")
277  << modportType.getModport() << " in symbol table.";
278  auto iface = cast<circt::sv::InterfaceOp>(modport->getParentOp());
279  Type esiDataType = getEsiDataType(iface);
280  if (!esiDataType)
281  return op->emitOpError("Interface is not a valid ESI interface.");
282  if (esiDataType != chanType.getInner())
283  return op->emitOpError("Operation specifies ")
284  << chanType << " but type inside doesn't match interface data type "
285  << esiDataType << ".";
286  return success();
287 }
288 
289 LogicalResult WrapSVInterfaceOp::verify() {
290  auto modportType = cast<circt::sv::ModportType>(getInterfaceSink().getType());
291  auto chanType = cast<ChannelType>(getOutput().getType());
292  return verifySVInterface(*this, modportType, chanType);
293 }
294 
295 circt::esi::ChannelType WrapSVInterfaceOp::channelType() {
296  return cast<circt::esi::ChannelType>(getOutput().getType());
297 }
298 
299 LogicalResult UnwrapSVInterfaceOp::verify() {
300  auto modportType =
301  cast<circt::sv::ModportType>(getInterfaceSource().getType());
302  auto chanType = cast<ChannelType>(getChanInput().getType());
303  return verifySVInterface(*this, modportType, chanType);
304 }
305 
306 circt::esi::ChannelType UnwrapSVInterfaceOp::channelType() {
307  return cast<circt::esi::ChannelType>(getChanInput().getType());
308 }
309 
310 LogicalResult WrapWindow::verify() {
311  hw::UnionType expectedInput = getWindow().getType().getLoweredType();
312  if (expectedInput == getFrame().getType())
313  return success();
314  return emitOpError("Expected input type is ") << expectedInput;
315 }
316 
317 LogicalResult
318 UnwrapWindow::inferReturnTypes(MLIRContext *, std::optional<Location>,
319  ValueRange operands, DictionaryAttr,
320  mlir::OpaqueProperties, mlir::RegionRange,
321  SmallVectorImpl<Type> &inferredReturnTypes) {
322  auto windowType = cast<WindowType>(operands.front().getType());
323  inferredReturnTypes.push_back(windowType.getLoweredType());
324  return success();
325 }
326 
327 /// Determine the input type ('frame') from the return type ('window').
328 static bool parseInferWindowRet(OpAsmParser &p, Type &frame, Type &windowOut) {
329  WindowType window;
330  if (p.parseType(window))
331  return true;
332  windowOut = window;
333  frame = window.getLoweredType();
334  return false;
335 }
336 
337 static void printInferWindowRet(OpAsmPrinter &p, Operation *, Type,
338  Type window) {
339  p << window;
340 }
341 
342 //===----------------------------------------------------------------------===//
343 // Services ops.
344 //===----------------------------------------------------------------------===//
345 
346 /// Get the port declaration op for the specified service decl, port name.
347 static FailureOr<ServiceDeclOpInterface>
348 getServiceDecl(Operation *op, SymbolTableCollection &symbolTable,
349  hw::InnerRefAttr servicePort) {
350  ModuleOp top = op->getParentOfType<mlir::ModuleOp>();
351  SymbolTable &topSyms = symbolTable.getSymbolTable(top);
352 
353  StringAttr modName = servicePort.getModule();
354  auto serviceDecl = topSyms.lookup<ServiceDeclOpInterface>(modName);
355  if (!serviceDecl)
356  return op->emitOpError("Could not find service declaration ")
357  << servicePort.getModuleRef();
358  return serviceDecl;
359 }
360 
361 /// Get the port info for the specified service decl and port name.
362 static FailureOr<ServicePortInfo>
363 getServicePortInfo(Operation *op, SymbolTableCollection &symbolTable,
364  hw::InnerRefAttr servicePort) {
365  auto serviceDecl = getServiceDecl(op, symbolTable, servicePort);
366  if (failed(serviceDecl))
367  return failure();
368  auto portInfo = serviceDecl->getPortInfo(servicePort.getName());
369  if (failed(portInfo))
370  return op->emitOpError("Could not locate port ") << servicePort.getName();
371  return portInfo;
372 }
373 
374 /// Check that the channels on two bundles match allowing for AnyType in the
375 /// 'svc' bundle.
376 static LogicalResult checkTypeMatch(Operation *req,
377  ChannelBundleType svcBundleType,
378  ChannelBundleType reqBundleType,
379  bool skipDirectionCheck) {
380  auto *ctxt = svcBundleType.getContext();
381  auto anyChannelType = ChannelType::get(ctxt, AnyType::get(ctxt));
382 
383  if (svcBundleType.getChannels().size() != reqBundleType.getChannels().size())
384  return req->emitOpError(
385  "Request port bundle channel count does not match service "
386  "port bundle channel count");
387 
388  // Build fast lookup.
389  DenseMap<StringAttr, BundledChannel> declBundleChannels;
390  for (BundledChannel bc : svcBundleType.getChannels())
391  declBundleChannels[bc.name] = bc;
392 
393  // Check all the channels.
394  for (BundledChannel bc : reqBundleType.getChannels()) {
395  auto f = declBundleChannels.find(bc.name);
396  if (f == declBundleChannels.end())
397  return req->emitOpError(
398  "Request channel name not found in service port bundle");
399  if (!skipDirectionCheck && f->second.direction != bc.direction)
400  return req->emitOpError(
401  "Request channel direction does not match service "
402  "port bundle channel direction");
403 
404  if (f->second.type != bc.type && f->second.type != anyChannelType)
405  return req->emitOpError(
406  "Request channel type does not match service port "
407  "bundle channel type");
408  }
409  return success();
410 }
411 
412 LogicalResult
413 RequestConnectionOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
414  auto svcPort = getServicePortInfo(*this, symbolTable, getServicePortAttr());
415  if (failed(svcPort))
416  return failure();
417  return checkTypeMatch(*this, svcPort->type, getToClient().getType(), false);
418 }
419 
420 LogicalResult ServiceImplementConnReqOp::verifySymbolUses(
421  SymbolTableCollection &symbolTable) {
422  auto svcPort = getServicePortInfo(*this, symbolTable, getServicePortAttr());
423  if (failed(svcPort))
424  return failure();
425  return checkTypeMatch(*this, svcPort->type, getToClient().getType(), true);
426 }
427 
428 void CustomServiceDeclOp::getPortList(SmallVectorImpl<ServicePortInfo> &ports) {
429  for (auto toClient : getOps<ServiceDeclPortOp>())
430  ports.push_back(ServicePortInfo{
431  hw::InnerRefAttr::get(getSymNameAttr(), toClient.getInnerSymAttr()),
432  toClient.getToClientType()});
433 }
434 
435 //===----------------------------------------------------------------------===//
436 // Bundle ops.
437 //===----------------------------------------------------------------------===//
438 
439 static ParseResult
440 parseUnPackBundleType(OpAsmParser &parser,
441  SmallVectorImpl<Type> &toChannelTypes,
442  SmallVectorImpl<Type> &fromChannelTypes, Type &type) {
443 
444  ChannelBundleType bundleType;
445  if (parser.parseType(bundleType))
446  return failure();
447  type = bundleType;
448 
449  for (BundledChannel ch : bundleType.getChannels())
450  if (ch.direction == ChannelDirection::to)
451  toChannelTypes.push_back(ch.type);
452  else if (ch.direction == ChannelDirection::from)
453  fromChannelTypes.push_back(ch.type);
454  else
455  assert(false && "Channel direction invalid");
456  return success();
457 }
458 template <typename T3, typename T4>
459 static void printUnPackBundleType(OpAsmPrinter &p, Operation *, T3, T4,
460  Type bundleType) {
461  p.printType(bundleType);
462 }
463 void UnpackBundleOp::build(::mlir::OpBuilder &odsBuilder,
464  ::mlir::OperationState &odsState, Value bundle,
465  mlir::ValueRange fromChannels) {
466  for (BundledChannel ch :
467  cast<ChannelBundleType>(bundle.getType()).getChannels())
468  if (ch.direction == ChannelDirection::to)
469  odsState.addTypes(ch.type);
470  odsState.addOperands(bundle);
471  odsState.addOperands(fromChannels);
472 }
473 
474 LogicalResult PackBundleOp::verify() {
475  if (!getBundle().hasOneUse())
476  return emitOpError("bundles must have exactly one user");
477  return success();
478 }
479 void PackBundleOp::build(::mlir::OpBuilder &odsBuilder,
480  ::mlir::OperationState &odsState,
481  ChannelBundleType bundleType,
482  mlir::ValueRange toChannels) {
483  odsState.addTypes(bundleType);
484  for (BundledChannel ch : cast<ChannelBundleType>(bundleType).getChannels())
485  if (ch.direction == ChannelDirection::from)
486  odsState.addTypes(ch.type);
487  odsState.addOperands(toChannels);
488 }
489 
490 LogicalResult UnpackBundleOp::verify() {
491  if (!getBundle().hasOneUse())
492  return emitOpError("bundles must have exactly one user");
493  return success();
494 }
495 
497  if (getNumResults() == 0)
498  return;
499  setNameFn(getResult(0), "bundle");
500  for (auto [idx, from] : llvm::enumerate(llvm::make_filter_range(
501  getBundle().getType().getChannels(), [](BundledChannel ch) {
502  return ch.direction == ChannelDirection::from;
503  })))
504  if (idx + 1 < getNumResults())
505  setNameFn(getResult(idx + 1), from.name.getValue());
506 }
507 
509  for (auto [idx, to] : llvm::enumerate(llvm::make_filter_range(
510  getBundle().getType().getChannels(), [](BundledChannel ch) {
511  return ch.direction == ChannelDirection::to;
512  })))
513  if (idx < getNumResults())
514  setNameFn(getResult(idx), to.name.getValue());
515 }
516 //===----------------------------------------------------------------------===//
517 // Structural ops.
518 //===----------------------------------------------------------------------===//
519 
520 LogicalResult ESIPureModuleOp::verify() {
521  ESIDialect *esiDialect = getContext()->getLoadedDialect<ESIDialect>();
522  Block &body = getBody().front();
523  auto channelOrOutput = [](Value v) {
524  if (isa<ChannelType, ChannelBundleType>(v.getType()))
525  return true;
526  if (v.getUsers().empty())
527  return false;
528  return llvm::all_of(v.getUsers(), [](Operation *op) {
529  return isa<ESIPureModuleOutputOp>(op);
530  });
531  };
532 
533  DenseMap<StringAttr, std::tuple<hw::ModulePort::Direction, Type, Operation *>>
534  ports;
535  for (Operation &op : body.getOperations()) {
536  if (igraph::InstanceOpInterface inst =
537  dyn_cast<igraph::InstanceOpInterface>(op)) {
538  if (llvm::any_of(op.getOperands(), [](Value v) {
539  return !(isa<ChannelType, ChannelBundleType>(v.getType()) ||
540  isa<ESIPureModuleInputOp>(v.getDefiningOp()));
541  }))
542  return inst.emitOpError(
543  "instances in ESI pure modules can only contain channel ports or "
544  "ports driven by 'input' ops");
545  if (!llvm::all_of(op.getResults(), channelOrOutput))
546  return inst.emitOpError(
547  "instances in ESI pure modules can only contain channel ports or "
548  "drive only 'outputs'");
549  } else {
550  // Pure modules can only contain instance ops and ESI ops.
551  if (op.getDialect() != esiDialect)
552  return op.emitOpError("operation not allowed in ESI pure modules");
553  }
554 
555  // Check for port validity.
556  if (auto port = dyn_cast<ESIPureModuleInputOp>(op)) {
557  auto existing = ports.find(port.getNameAttr());
558  Type portType = port.getResult().getType();
559  if (existing != ports.end()) {
560  auto [dir, type, op] = existing->getSecond();
561  if (dir != hw::ModulePort::Direction::Input || type != portType)
562  return (port.emitOpError("port '")
563  << port.getName() << "' previously declared as type " << type)
564  .attachNote(op->getLoc());
565  }
566  ports[port.getNameAttr()] = std::make_tuple(
567  hw::ModulePort::Direction::Input, portType, port.getOperation());
568  } else if (auto port = dyn_cast<ESIPureModuleOutputOp>(op)) {
569  auto existing = ports.find(port.getNameAttr());
570  if (existing != ports.end())
571  return (port.emitOpError("port '")
572  << port.getName() << "' previously declared")
573  .attachNote(std::get<2>(existing->getSecond())->getLoc());
574  ports[port.getNameAttr()] =
575  std::make_tuple(hw::ModulePort::Direction::Input,
576  port.getValue().getType(), port.getOperation());
577  }
578  }
579  return success();
580 }
581 
582 hw::ModuleType ESIPureModuleOp::getHWModuleType() {
583  return hw::ModuleType::get(getContext(), {});
584 }
585 
586 SmallVector<::circt::hw::PortInfo> ESIPureModuleOp::getPortList() { return {}; }
588  ::llvm::report_fatal_error("not supported");
589 }
590 
591 size_t ESIPureModuleOp::getNumPorts() { return 0; }
592 size_t ESIPureModuleOp::getNumInputPorts() { return 0; }
593 size_t ESIPureModuleOp::getNumOutputPorts() { return 0; }
594 size_t ESIPureModuleOp::getPortIdForInputId(size_t) {
595  assert(0 && "Out of bounds input port id");
596  return ~0ULL;
597 }
598 size_t ESIPureModuleOp::getPortIdForOutputId(size_t) {
599  assert(0 && "Out of bounds output port id");
600  return ~0ULL;
601 }
602 
603 SmallVector<Location> ESIPureModuleOp::getAllPortLocs() {
604  SmallVector<Location> retval;
605  return retval;
606 }
607 
608 void ESIPureModuleOp::setAllPortLocsAttrs(ArrayRef<Attribute> locs) {
609  emitError("No ports for port locations");
610 }
611 
612 void ESIPureModuleOp::setAllPortNames(ArrayRef<Attribute> names) {
613  emitError("No ports for port naming");
614 }
615 
616 void ESIPureModuleOp::setAllPortAttrs(ArrayRef<Attribute> attrs) {
617  emitError("No ports for port attributes");
618 }
619 
620 void ESIPureModuleOp::removeAllPortAttrs() {
621  emitError("No ports for port attributes)");
622 }
623 
624 ArrayRef<Attribute> ESIPureModuleOp::getAllPortAttrs() { return {}; }
625 
626 void ESIPureModuleOp::setHWModuleType(hw::ModuleType type) {
627  emitError("No ports for port types");
628 }
629 
630 //===----------------------------------------------------------------------===//
631 // Manifest ops.
632 //===----------------------------------------------------------------------===//
633 
634 StringRef ServiceImplRecordOp::getManifestClass() { return "service"; }
635 
636 void ServiceImplRecordOp::getDetails(SmallVectorImpl<NamedAttribute> &results) {
637  auto *ctxt = getContext();
638  // AppID, optionally the service name, implementation name and details.
639  results.emplace_back(getAppIDAttrName(), getAppIDAttr());
640  if (getService())
641  results.emplace_back(getServiceAttrName(), getServiceAttr());
642  results.emplace_back(getServiceImplNameAttrName(), getServiceImplNameAttr());
643  // Don't add another level for the implementation details.
644  for (auto implDetail : getImplDetailsAttr().getValue())
645  results.push_back(implDetail);
646 
647  // All of the manifest data contained by this op.
648  SmallVector<Attribute, 8> reqDetails;
649  for (auto reqDetail : getReqDetails().front().getOps<IsManifestData>())
650  reqDetails.push_back(reqDetail.getDetailsAsDict());
651  results.emplace_back(StringAttr::get(ctxt, "client_details"),
652  ArrayAttr::get(ctxt, reqDetails));
653 }
654 
655 bool parseServiceImplRecordReqDetails(OpAsmParser &parser,
656  Region &reqDetailsRegion) {
657  parser.parseOptionalRegion(reqDetailsRegion);
658  if (reqDetailsRegion.empty())
659  reqDetailsRegion.emplaceBlock();
660  return false;
661 }
662 
663 void printServiceImplRecordReqDetails(OpAsmPrinter &p, ServiceImplRecordOp,
664  Region &reqDetailsRegion) {
665  if (!reqDetailsRegion.empty() && !reqDetailsRegion.front().empty())
666  p.printRegion(reqDetailsRegion, /*printEntryBlockArgs=*/false,
667  /*printBlockTerminators=*/false);
668 }
669 
670 StringRef ServiceImplClientRecordOp::getManifestClass() {
671  return "service_client";
672 }
673 void ServiceImplClientRecordOp::getDetails(
674  SmallVectorImpl<NamedAttribute> &results) {
675  // Relative AppID path, service port, and implementation details. Don't add
676  // the bundle type since it is meaningless to the host and just clutters the
677  // output.
678  results.emplace_back(getRelAppIDPathAttrName(), getRelAppIDPathAttr());
679  results.emplace_back(getServicePortAttrName(), getServicePortAttr());
680  // Don't add another level for the implementation details.
681  for (auto implDetail : getImplDetailsAttr().getValue())
682  results.push_back(implDetail);
683 }
684 
685 StringRef ServiceRequestRecordOp::getManifestClass() { return "client_port"; }
686 
687 void ServiceRequestRecordOp::getDetails(
688  SmallVectorImpl<NamedAttribute> &results) {
689  auto *ctxt = getContext();
690  results.emplace_back(StringAttr::get(ctxt, "appID"), getRequestorAttr());
691  results.emplace_back(getBundleTypeAttrName(), getBundleTypeAttr());
692  results.emplace_back(getServicePortAttrName(), getServicePortAttr());
693  if (auto stdSvc = getStdServiceAttr())
694  results.emplace_back(getStdServiceAttrName(), getStdServiceAttr());
695 }
696 
697 StringRef SymbolMetadataOp::getManifestClass() { return "sym_info"; }
698 
699 #define GET_OP_CLASSES
700 #include "circt/Dialect/ESI/ESI.cpp.inc"
701 
702 #include "circt/Dialect/ESI/ESIInterfaces.cpp.inc"
assert(baseType &&"element must be base type")
return wrap(CMemoryType::get(unwrap(ctx), baseType, numElements))
static bool parseInferWindowRet(OpAsmParser &p, Type &frame, Type &windowOut)
Determine the input type ('frame') from the return type ('window').
Definition: ESIOps.cpp:328
ParseResult parseWrapFIFOType(OpAsmParser &p, Type &dataType, Type &chanInputType)
Definition: ESIOps.cpp:207
static LogicalResult verifySVInterface(Operation *op, circt::sv::ModportType modportType, ChannelType chanType)
Verify that the modport type of 'modportArg' points to an interface which looks like an ESI interface...
Definition: ESIOps.cpp:269
static LogicalResult checkTypeMatch(Operation *req, ChannelBundleType svcBundleType, ChannelBundleType reqBundleType, bool skipDirectionCheck)
Check that the channels on two bundles match allowing for AnyType in the 'svc' bundle.
Definition: ESIOps.cpp:376
void printServiceImplRecordReqDetails(OpAsmPrinter &p, ServiceImplRecordOp, Region &reqDetailsRegion)
Definition: ESIOps.cpp:663
static FailureOr< ServicePortInfo > getServicePortInfo(Operation *op, SymbolTableCollection &symbolTable, hw::InnerRefAttr servicePort)
Get the port info for the specified service decl and port name.
Definition: ESIOps.cpp:363
static Type getEsiDataType(circt::sv::InterfaceOp iface)
If 'iface' looks like an ESI interface, return the inner data type.
Definition: ESIOps.cpp:254
static FailureOr< ServiceDeclOpInterface > getServiceDecl(Operation *op, SymbolTableCollection &symbolTable, hw::InnerRefAttr servicePort)
Get the port declaration op for the specified service decl, port name.
Definition: ESIOps.cpp:348
static void printUnPackBundleType(OpAsmPrinter &p, Operation *, T3, T4, Type bundleType)
Definition: ESIOps.cpp:459
static ParseResult parseUnPackBundleType(OpAsmParser &parser, SmallVectorImpl< Type > &toChannelTypes, SmallVectorImpl< Type > &fromChannelTypes, Type &type)
Definition: ESIOps.cpp:440
static void printInferWindowRet(OpAsmPrinter &p, Operation *, Type, Type window)
Definition: ESIOps.cpp:337
void printWrapFIFOType(OpAsmPrinter &p, WrapFIFOOp wrap, Type dataType, Type chanType)
Definition: ESIOps.cpp:220
bool parseServiceImplRecordReqDetails(OpAsmParser &parser, Region &reqDetailsRegion)
Definition: ESIOps.cpp:655
static SmallVector< Location > getAllPortLocs(ModTy module)
Definition: HWOps.cpp:1192
static void setAllPortNames(ArrayRef< Attribute > names, ModTy module)
Definition: HWOps.cpp:1262
static void setHWModuleType(ModTy &mod, ModuleType type)
Definition: HWOps.cpp:1335
static SmallVector< PortInfo > getPortList(ModuleTy &mod)
Definition: HWOps.cpp:1414
static PortInfo getPort(ModuleTy &mod, size_t idx)
Definition: HWOps.cpp:1434
@ Input
Definition: HW.h:35
static LogicalResult verify(Value clock, bool eventExists, mlir::Location loc)
Definition: SVOps.cpp:2443
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
LogicalResult inferReturnTypes(MLIRContext *context, std::optional< Location > loc, ValueRange operands, DictionaryAttr attrs, mlir::OpaqueProperties properties, mlir::RegionRange regions, SmallVectorImpl< Type > &results, llvm::function_ref< FIRRTLType(ValueRange, ArrayRef< NamedAttribute >, std::optional< Location >)> callback)
size_t getNumPorts(Operation *op)
Return the number of ports in a module-like thing (modules, memories, etc)
Definition: FIRRTLOps.cpp:298
void getAsmResultNames(OpAsmSetValueNameFn setNameFn, StringRef instanceName, ArrayAttr resultNames, ValueRange results)
Suggest a name for each result value based on the saved result names attribute.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
Definition: LLVM.h:182
ChannelDirection direction
Definition: ESITypes.h:38
Describes a service port.
Definition: ESIOps.h:31
This holds the name, type, direction of a module's ports.