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