CIRCT  19.0.0git
ESILowerPorts.cpp
Go to the documentation of this file.
1 //===- ESILowerPorts.cpp - Lower ESI ports pass ----------------*- 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 #include "../PassDetails.h"
10 
12 #include "circt/Dialect/HW/HWOps.h"
14 #include "circt/Dialect/SV/SVOps.h"
16 #include "circt/Support/LLVM.h"
17 #include "circt/Support/SymCache.h"
18 
19 #include "mlir/Transforms/DialectConversion.h"
20 
21 namespace circt {
22 namespace esi {
23 #define GEN_PASS_DEF_LOWERESIPORTS
24 #include "circt/Dialect/ESI/ESIPasses.h.inc"
25 } // namespace esi
26 } // namespace circt
27 
28 using namespace circt;
29 using namespace circt::esi;
30 using namespace circt::esi::detail;
31 using namespace circt::hw;
32 
33 // Returns either the string dialect attr stored in 'op' going by the name
34 // 'attrName' or 'def' if the attribute doesn't exist in 'op'.
35 inline static StringRef getStringAttributeOr(Operation *op, StringRef attrName,
36  StringRef def) {
37  auto attr = op->getAttrOfType<StringAttr>(attrName);
38  if (attr)
39  return attr.getValue();
40  return def;
41 }
42 
43 namespace {
44 
45 // Base class for all ESI signaling standards, which handles potentially funky
46 // attribute-based naming conventions.
47 struct ESISignalingStandad : public PortConversion {
48  ESISignalingStandad(PortConverterImpl &converter, hw::PortInfo origPort)
49  : PortConversion(converter, origPort) {}
50 };
51 
52 /// Implement the Valid/Ready signaling standard.
53 class ValidReady : public ESISignalingStandad {
54 public:
55  ValidReady(PortConverterImpl &converter, hw::PortInfo origPort)
56  : ESISignalingStandad(converter, origPort), validPort(origPort),
57  readyPort(origPort) {}
58 
59  void mapInputSignals(OpBuilder &b, Operation *inst, Value instValue,
60  SmallVectorImpl<Value> &newOperands,
61  ArrayRef<Backedge> newResults) override;
62  void mapOutputSignals(OpBuilder &b, Operation *inst, Value instValue,
63  SmallVectorImpl<Value> &newOperands,
64  ArrayRef<Backedge> newResults) override;
65 
66 private:
67  void buildInputSignals() override;
68  void buildOutputSignals() override;
69 
70  // Keep around information about the port numbers of the relevant ports and
71  // use that later to update the instances.
72  PortInfo validPort, readyPort, dataPort;
73 };
74 
75 /// Implement the FIFO signaling standard.
76 class FIFO : public ESISignalingStandad {
77 public:
78  FIFO(PortConverterImpl &converter, hw::PortInfo origPort)
79  : ESISignalingStandad(converter, origPort) {}
80 
81  void mapInputSignals(OpBuilder &b, Operation *inst, Value instValue,
82  SmallVectorImpl<Value> &newOperands,
83  ArrayRef<Backedge> newResults) override;
84  void mapOutputSignals(OpBuilder &b, Operation *inst, Value instValue,
85  SmallVectorImpl<Value> &newOperands,
86  ArrayRef<Backedge> newResults) override;
87 
88 private:
89  void buildInputSignals() override;
90  void buildOutputSignals() override;
91 
92  // Keep around information about the port numbers of the relevant ports and
93  // use that later to update the instances.
94  PortInfo rdenPort, emptyPort, dataPort;
95 };
96 
97 class ESIPortConversionBuilder : public PortConversionBuilder {
98 public:
100  FailureOr<std::unique_ptr<PortConversion>> build(hw::PortInfo port) override {
101  return llvm::TypeSwitch<Type, FailureOr<std::unique_ptr<PortConversion>>>(
102  port.type)
103  .Case([&](esi::ChannelType chanTy)
105  // Determine which ESI signaling standard is specified.
106  ChannelSignaling signaling = chanTy.getSignaling();
107  if (signaling == ChannelSignaling::ValidReady)
108  return {std::make_unique<ValidReady>(converter, port)};
109 
110  if (signaling == ChannelSignaling::FIFO0)
111  return {std::make_unique<FIFO>(converter, port)};
112 
113  auto error = converter.getModule().emitOpError(
114  "encountered unknown signaling standard on port '")
115  << stringifyEnum(signaling) << "'";
116  error.attachNote(port.loc);
117  return error;
118  })
119  .Default([&](auto) { return PortConversionBuilder::build(port); });
120  }
121 };
122 } // namespace
123 
124 void ValidReady::buildInputSignals() {
125  Type i1 = IntegerType::get(getContext(), 1, IntegerType::Signless);
126 
127  StringRef inSuffix =
128  getStringAttributeOr(converter.getModule(), extModPortInSuffix, "");
129  StringRef validSuffix(getStringAttributeOr(converter.getModule(),
130  extModPortValidSuffix, "_valid"));
131 
132  // When we find one, add a data and valid signal to the new args.
133  Value data = converter.createNewInput(
134  origPort, inSuffix, cast<esi::ChannelType>(origPort.type).getInner(),
135  dataPort);
136  Value valid =
137  converter.createNewInput(origPort, validSuffix + inSuffix, i1, validPort);
138 
139  Value ready;
140  if (body) {
141  ImplicitLocOpBuilder b(origPort.loc, body, body->begin());
142  // Build the ESI wrap operation to translate the lowered signals to what
143  // they were. (A later pass takes care of eliminating the ESI ops.)
144  auto wrap = b.create<WrapValidReadyOp>(data, valid);
145  ready = wrap.getReady();
146  // Replace uses of the old ESI port argument with the new one from the
147  // wrap.
148  body->getArgument(origPort.argNum).replaceAllUsesWith(wrap.getChanOutput());
149  }
150 
151  StringRef readySuffix = getStringAttributeOr(converter.getModule(),
152  extModPortReadySuffix, "_ready");
153  StringRef outSuffix =
154  getStringAttributeOr(converter.getModule(), extModPortOutSuffix, "");
155  converter.createNewOutput(origPort, readySuffix + outSuffix, i1, ready,
156  readyPort);
157 }
158 
159 void ValidReady::mapInputSignals(OpBuilder &b, Operation *inst, Value instValue,
160  SmallVectorImpl<Value> &newOperands,
161  ArrayRef<Backedge> newResults) {
162  auto unwrap = b.create<UnwrapValidReadyOp>(inst->getLoc(),
163  inst->getOperand(origPort.argNum),
164  newResults[readyPort.argNum]);
165  newOperands[dataPort.argNum] = unwrap.getRawOutput();
166  newOperands[validPort.argNum] = unwrap.getValid();
167 }
168 
169 void ValidReady::buildOutputSignals() {
170  Type i1 = IntegerType::get(getContext(), 1, IntegerType::Signless);
171 
172  StringRef readySuffix = getStringAttributeOr(converter.getModule(),
173  extModPortReadySuffix, "_ready");
174  StringRef inSuffix =
175  getStringAttributeOr(converter.getModule(), extModPortInSuffix, "");
176 
177  Value ready =
178  converter.createNewInput(origPort, readySuffix + inSuffix, i1, readyPort);
179  Value data, valid;
180  if (body) {
181  auto *terminator = body->getTerminator();
182  ImplicitLocOpBuilder b(origPort.loc, terminator);
183 
184  auto unwrap = b.create<UnwrapValidReadyOp>(
185  terminator->getOperand(origPort.argNum), ready);
186  data = unwrap.getRawOutput();
187  valid = unwrap.getValid();
188  }
189 
190  // New outputs.
191  StringRef outSuffix =
192  getStringAttributeOr(converter.getModule(), extModPortOutSuffix, "");
193  StringRef validSuffix = getStringAttributeOr(converter.getModule(),
194  extModPortValidSuffix, "_valid");
195  converter.createNewOutput(origPort, outSuffix,
196  cast<esi::ChannelType>(origPort.type).getInner(),
197  data, dataPort);
198  converter.createNewOutput(origPort, validSuffix + outSuffix, i1, valid,
199  validPort);
200 }
201 
202 void ValidReady::mapOutputSignals(OpBuilder &b, Operation *inst,
203  Value instValue,
204  SmallVectorImpl<Value> &newOperands,
205  ArrayRef<Backedge> newResults) {
206  auto wrap =
207  b.create<WrapValidReadyOp>(inst->getLoc(), newResults[dataPort.argNum],
208  newResults[validPort.argNum]);
209  inst->getResult(origPort.argNum).replaceAllUsesWith(wrap.getChanOutput());
210  newOperands[readyPort.argNum] = wrap.getReady();
211 }
212 
213 void FIFO::buildInputSignals() {
214  Type i1 = IntegerType::get(getContext(), 1, IntegerType::Signless);
215  auto chanTy = cast<ChannelType>(origPort.type);
216 
217  StringRef rdenSuffix(getStringAttributeOr(converter.getModule(),
218  extModPortRdenSuffix, "_rden"));
219  StringRef emptySuffix(getStringAttributeOr(converter.getModule(),
220  extModPortEmptySuffix, "_empty"));
221  StringRef inSuffix =
222  getStringAttributeOr(converter.getModule(), extModPortInSuffix, "");
223  StringRef outSuffix =
224  getStringAttributeOr(converter.getModule(), extModPortOutSuffix, "");
225 
226  // When we find one, add a data and valid signal to the new args.
227  Value data = converter.createNewInput(
228  origPort, inSuffix, cast<esi::ChannelType>(origPort.type).getInner(),
229  dataPort);
230  Value empty =
231  converter.createNewInput(origPort, emptySuffix + inSuffix, i1, emptyPort);
232 
233  Value rden;
234  if (body) {
235  ImplicitLocOpBuilder b(origPort.loc, body, body->begin());
236  // Build the ESI wrap operation to translate the lowered signals to what
237  // they were. (A later pass takes care of eliminating the ESI ops.)
238  auto wrap = b.create<WrapFIFOOp>(ArrayRef<Type>({chanTy, b.getI1Type()}),
239  data, empty);
240  rden = wrap.getRden();
241  // Replace uses of the old ESI port argument with the new one from the
242  // wrap.
243  body->getArgument(origPort.argNum).replaceAllUsesWith(wrap.getChanOutput());
244  }
245 
246  converter.createNewOutput(origPort, rdenSuffix + outSuffix, i1, rden,
247  rdenPort);
248 }
249 
250 void FIFO::mapInputSignals(OpBuilder &b, Operation *inst, Value instValue,
251  SmallVectorImpl<Value> &newOperands,
252  ArrayRef<Backedge> newResults) {
253  auto unwrap =
254  b.create<UnwrapFIFOOp>(inst->getLoc(), inst->getOperand(origPort.argNum),
255  newResults[rdenPort.argNum]);
256  newOperands[dataPort.argNum] = unwrap.getData();
257  newOperands[emptyPort.argNum] = unwrap.getEmpty();
258 }
259 
260 void FIFO::buildOutputSignals() {
261  Type i1 = IntegerType::get(getContext(), 1, IntegerType::Signless);
262 
263  StringRef inSuffix =
264  getStringAttributeOr(converter.getModule(), extModPortInSuffix, "");
265  StringRef outSuffix =
266  getStringAttributeOr(converter.getModule(), extModPortOutSuffix, "");
267  StringRef rdenSuffix(getStringAttributeOr(converter.getModule(),
268  extModPortRdenSuffix, "_rden"));
269  StringRef emptySuffix(getStringAttributeOr(converter.getModule(),
270  extModPortEmptySuffix, "_empty"));
271  Value rden =
272  converter.createNewInput(origPort, rdenSuffix + inSuffix, i1, rdenPort);
273  Value data, empty;
274  if (body) {
275  auto *terminator = body->getTerminator();
276  ImplicitLocOpBuilder b(origPort.loc, terminator);
277 
278  auto unwrap =
279  b.create<UnwrapFIFOOp>(terminator->getOperand(origPort.argNum), rden);
280  data = unwrap.getData();
281  empty = unwrap.getEmpty();
282  }
283 
284  // New outputs.
285  converter.createNewOutput(origPort, outSuffix,
286  cast<esi::ChannelType>(origPort.type).getInner(),
287  data, dataPort);
288  converter.createNewOutput(origPort, emptySuffix + outSuffix, i1, empty,
289  emptyPort);
290 }
291 
292 void FIFO::mapOutputSignals(OpBuilder &b, Operation *inst, Value instValue,
293  SmallVectorImpl<Value> &newOperands,
294  ArrayRef<Backedge> newResults) {
295  auto wrap = b.create<WrapFIFOOp>(
296  inst->getLoc(), ArrayRef<Type>({origPort.type, b.getI1Type()}),
297  newResults[dataPort.argNum], newResults[emptyPort.argNum]);
298  inst->getResult(origPort.argNum).replaceAllUsesWith(wrap.getChanOutput());
299  newOperands[rdenPort.argNum] = wrap.getRden();
300 }
301 
302 namespace {
303 /// Convert all the ESI ports on modules to some lower construct. SV
304 /// interfaces for now on external modules, ready/valid to modules defined
305 /// internally. In the future, it may be possible to select a different
306 /// format.
307 struct ESIPortsPass : public circt::esi::impl::LowerESIPortsBase<ESIPortsPass> {
308  void runOnOperation() override;
309 
310 private:
311  bool updateFunc(HWModuleExternOp mod);
312  void updateInstance(HWModuleExternOp mod, InstanceOp inst);
313  ESIHWBuilder *build;
314 };
315 } // anonymous namespace
316 
317 /// Iterate through the `hw.module[.extern]`s and lower their ports.
318 void ESIPortsPass::runOnOperation() {
319  ModuleOp top = getOperation();
320  ESIHWBuilder b(top);
321  build = &b;
322 
323  // Find all externmodules and try to modify them. Remember the modified
324  // ones.
325  DenseMap<SymbolRefAttr, HWModuleExternOp> externModsMutated;
326  for (auto mod : top.getOps<HWModuleExternOp>())
327  if (mod->hasAttrOfType<UnitAttr>(extModBundleSignalsAttrName) &&
328  updateFunc(mod))
329  externModsMutated[FlatSymbolRefAttr::get(mod)] = mod;
330 
331  // Find all instances and update them.
332  top.walk([&externModsMutated, this](InstanceOp inst) {
333  auto mapIter = externModsMutated.find(inst.getModuleNameAttr());
334  if (mapIter != externModsMutated.end())
335  updateInstance(mapIter->second, inst);
336  });
337 
338  // Find all modules and run port conversion on them.
339  circt::hw::InstanceGraph &instanceGraph =
340  getAnalysis<circt::hw::InstanceGraph>();
341 
342  for (auto mod : top.getOps<HWMutableModuleLike>()) {
343  if (failed(
344  PortConverter<ESIPortConversionBuilder>(instanceGraph, mod).run()))
345  return signalPassFailure();
346  }
347 
348  build = nullptr;
349 }
350 
351 /// Convert all input and output ChannelTypes into SV Interfaces. For inputs,
352 /// just switch the type to `ModportType`. For outputs, append a `ModportType`
353 /// to the inputs and remove the output channel from the results. Returns true
354 /// if 'mod' was updated. Delay updating the instances to amortize the IR walk
355 /// over all the module updates.
356 bool ESIPortsPass::updateFunc(HWModuleExternOp mod) {
357  auto *ctxt = &getContext();
358 
359  bool updated = false;
360 
361  SmallVector<Attribute> newArgNames, newResultNames;
362  SmallVector<Location> newArgLocs, newResultLocs;
363 
364  // Reconstruct the list of operand types, changing the type whenever an ESI
365  // port is found.
366  SmallVector<Type, 16> newArgTypes;
367  size_t nextArgNo = 0;
368  for (auto argTy : mod.getInputTypes()) {
369  auto chanTy = dyn_cast<ChannelType>(argTy);
370  newArgNames.push_back(mod.getInputNameAttr(nextArgNo));
371  newArgLocs.push_back(mod.getInputLoc(nextArgNo));
372  nextArgNo++;
373 
374  if (!chanTy) {
375  newArgTypes.push_back(argTy);
376  continue;
377  }
378 
379  // When we find one, construct an interface, and add the 'source' modport
380  // to the type list.
381  auto iface = build->getOrConstructInterface(chanTy);
382  newArgTypes.push_back(iface.getModportType(ESIHWBuilder::sourceStr));
383  updated = true;
384  }
385 
386  // Iterate through the results and append to one of the two below lists. The
387  // first for non-ESI-ports. The second, ports which have been re-located to
388  // an operand.
389  SmallVector<Type, 8> newResultTypes;
390  SmallVector<DictionaryAttr, 4> newResultAttrs;
391  for (size_t resNum = 0, numRes = mod.getNumOutputPorts(); resNum < numRes;
392  ++resNum) {
393  Type resTy = mod.getOutputTypes()[resNum];
394  auto chanTy = dyn_cast<ChannelType>(resTy);
395  auto resNameAttr = mod.getOutputNameAttr(resNum);
396  auto resLocAttr = mod.getOutputLoc(resNum);
397  if (!chanTy) {
398  newResultTypes.push_back(resTy);
399  newResultNames.push_back(resNameAttr);
400  newResultLocs.push_back(resLocAttr);
401  continue;
402  }
403 
404  // When we find one, construct an interface, and add the 'sink' modport to
405  // the type list.
406  sv::InterfaceOp iface = build->getOrConstructInterface(chanTy);
407  sv::ModportType sinkPort = iface.getModportType(ESIHWBuilder::sinkStr);
408  newArgTypes.push_back(sinkPort);
409  newArgNames.push_back(resNameAttr);
410  newArgLocs.push_back(resLocAttr);
411  updated = true;
412  }
413 
414  mod->removeAttr(extModBundleSignalsAttrName);
415  if (!updated)
416  return false;
417 
418  // Set the new types.
419  auto newFuncType = FunctionType::get(ctxt, newArgTypes, newResultTypes);
420  auto newModType =
421  hw::detail::fnToMod(newFuncType, newArgNames, newResultNames);
422  mod.setHWModuleType(newModType);
423  mod.setInputLocs(newArgLocs);
424  mod.setOutputLocs(newResultLocs);
425  return true;
426 }
427 
428 static StringRef getOperandName(Value operand) {
429  if (BlockArgument arg = dyn_cast<BlockArgument>(operand)) {
430  auto *op = arg.getParentBlock()->getParentOp();
431  if (HWModuleLike mod = dyn_cast_or_null<HWModuleLike>(op))
432  return mod.getInputName(arg.getArgNumber());
433  } else {
434  auto *srcOp = operand.getDefiningOp();
435  if (auto instOp = dyn_cast<InstanceOp>(srcOp))
436  return instOp.getInstanceName();
437 
438  if (auto srcName = srcOp->getAttrOfType<StringAttr>("name"))
439  return srcName.getValue();
440  }
441  return "";
442 }
443 
444 /// Create a reasonable name for a SV interface instance.
445 static std::string &constructInstanceName(Value operand, sv::InterfaceOp iface,
446  std::string &name) {
447  llvm::raw_string_ostream s(name);
448  // Drop the "IValidReady_" part of the interface name.
449  s << llvm::toLower(iface.getSymName()[12]) << iface.getSymName().substr(13);
450 
451  // Indicate to where the source is connected.
452  if (operand.hasOneUse()) {
453  Operation *dstOp = *operand.getUsers().begin();
454  if (auto instOp = dyn_cast<InstanceOp>(dstOp))
455  s << "To" << llvm::toUpper(instOp.getInstanceName()[0])
456  << instOp.getInstanceName().substr(1);
457  else if (auto dstName = dstOp->getAttrOfType<StringAttr>("name"))
458  s << "To" << dstName.getValue();
459  }
460 
461  // Indicate to where the sink is connected.
462  StringRef operName = getOperandName(operand);
463  if (!operName.empty())
464  s << "From" << llvm::toUpper(operName[0]) << operName.substr(1);
465  return s.str();
466 }
467 
468 /// Update an instance of an updated module by adding `esi.(un)wrap.iface`
469 /// around the instance. Create a new instance at the end from the lists built
470 /// up before.
471 void ESIPortsPass::updateInstance(HWModuleExternOp mod, InstanceOp inst) {
472  using namespace circt::sv;
473  circt::ImplicitLocOpBuilder instBuilder(inst.getLoc(), inst);
474 
475  // op counter for error reporting purposes.
476  size_t opNum = 0;
477  // List of new operands.
478  SmallVector<Value, 16> newOperands;
479 
480  // Fill the new operand list with old plain operands and mutated ones.
481  std::string nameStringBuffer; // raw_string_ostream uses std::string.
482  for (auto op : inst.getOperands()) {
483  auto instChanTy = dyn_cast<ChannelType>(op.getType());
484  if (!instChanTy) {
485  newOperands.push_back(op);
486  ++opNum;
487  continue;
488  }
489 
490  // Get the interface from the cache, and make sure it's the same one as
491  // being used in the module.
492  auto iface = build->getOrConstructInterface(instChanTy);
493  if (iface.getModportType(ESIHWBuilder::sourceStr) !=
494  mod.getInputTypes()[opNum]) {
495  inst.emitOpError("ESI ChannelType (operand #")
496  << opNum << ") doesn't match module!";
497  ++opNum;
498  newOperands.push_back(op);
499  continue;
500  }
501  ++opNum;
502 
503  // Build a gasket by instantiating an interface, connecting one end to an
504  // `esi.unwrap.iface` and the other end to the instance.
505  auto ifaceInst =
506  instBuilder.create<InterfaceInstanceOp>(iface.getInterfaceType());
507  nameStringBuffer.clear();
508  ifaceInst->setAttr(
509  "name",
510  StringAttr::get(mod.getContext(),
511  constructInstanceName(op, iface, nameStringBuffer)));
512  GetModportOp sinkModport =
513  instBuilder.create<GetModportOp>(ifaceInst, ESIHWBuilder::sinkStr);
514  instBuilder.create<UnwrapSVInterfaceOp>(op, sinkModport);
515  GetModportOp sourceModport =
516  instBuilder.create<GetModportOp>(ifaceInst, ESIHWBuilder::sourceStr);
517  // Finally, add the correct modport to the list of operands.
518  newOperands.push_back(sourceModport);
519  }
520 
521  // Go through the results and get both a list of the plain old values being
522  // produced and their types.
523  SmallVector<Value, 8> newResults;
524  SmallVector<Type, 8> newResultTypes;
525  for (size_t resNum = 0, numRes = inst.getNumResults(); resNum < numRes;
526  ++resNum) {
527  Value res = inst.getResult(resNum);
528  auto instChanTy = dyn_cast<ChannelType>(res.getType());
529  if (!instChanTy) {
530  newResults.push_back(res);
531  newResultTypes.push_back(res.getType());
532  continue;
533  }
534 
535  // Get the interface from the cache, and make sure it's the same one as
536  // being used in the module.
537  auto iface = build->getOrConstructInterface(instChanTy);
538  if (iface.getModportType(ESIHWBuilder::sinkStr) !=
539  mod.getInputTypes()[opNum]) {
540  inst.emitOpError("ESI ChannelType (result #")
541  << resNum << ", operand #" << opNum << ") doesn't match module!";
542  ++opNum;
543  newResults.push_back(res);
544  newResultTypes.push_back(res.getType());
545  continue;
546  }
547  ++opNum;
548 
549  // Build a gasket by instantiating an interface, connecting one end to an
550  // `esi.wrap.iface` and the other end to the instance. Append it to the
551  // operand list.
552  auto ifaceInst =
553  instBuilder.create<InterfaceInstanceOp>(iface.getInterfaceType());
554  nameStringBuffer.clear();
555  ifaceInst->setAttr(
556  "name",
557  StringAttr::get(mod.getContext(),
558  constructInstanceName(res, iface, nameStringBuffer)));
559  GetModportOp sourceModport =
560  instBuilder.create<GetModportOp>(ifaceInst, ESIHWBuilder::sourceStr);
561  auto newChannel =
562  instBuilder.create<WrapSVInterfaceOp>(res.getType(), sourceModport);
563  // Connect all the old users of the output channel with the newly
564  // wrapped replacement channel.
565  res.replaceAllUsesWith(newChannel);
566  GetModportOp sinkModport =
567  instBuilder.create<GetModportOp>(ifaceInst, ESIHWBuilder::sinkStr);
568  // And add the modport on the other side to the new operand list.
569  newOperands.push_back(sinkModport);
570  }
571 
572  // Create the new instance!
573  auto newInst = instBuilder.create<hw::InstanceOp>(
574  mod, inst.getInstanceNameAttr(), newOperands, inst.getParameters(),
575  inst.getInnerSymAttr());
576 
577  // Go through the old list of non-ESI result values, and replace them with
578  // the new non-ESI results.
579  for (size_t resNum = 0, numRes = newResults.size(); resNum < numRes;
580  ++resNum) {
581  newResults[resNum].replaceAllUsesWith(newInst.getResult(resNum));
582  }
583  // Erase the old instance!
584  inst.erase();
585 }
586 
587 std::unique_ptr<OperationPass<ModuleOp>>
589  return std::make_unique<ESIPortsPass>();
590 }
return wrap(CMemoryType::get(unwrap(ctx), baseType, numElements))
static std::string & constructInstanceName(Value operand, sv::InterfaceOp iface, std::string &name)
Create a reasonable name for a SV interface instance.
static StringRef getOperandName(Value operand)
static StringRef getStringAttributeOr(Operation *op, StringRef attrName, StringRef def)
static InstancePath empty
static EvaluatorValuePtr unwrap(OMEvaluatorValue c)
Definition: OM.cpp:96
Assist the lowering steps for conversions which need to create auxiliary IR.
Definition: PassDetails.h:56
static constexpr char sinkStr[]
Definition: PassDetails.h:78
static constexpr char sourceStr[]
Definition: PassDetails.h:77
HW-specific instance graph with a virtual entry node linking to all publicly visible modules.
PortConversionBuilder(PortConverterImpl &converter)
virtual FailureOr< std::unique_ptr< PortConversion > > build(hw::PortInfo port)
Base class for the port conversion of a particular port.
Definition: PortConverter.h:97
Channels are the basic communication primitives.
Definition: Types.h:63
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:54
constexpr StringRef extModPortValidSuffix
Suffix lowered valid ports with this suffix.
Definition: ESIDialect.h:50
constexpr StringRef extModPortRdenSuffix
Suffix lowered read enable ports with this suffix.
Definition: ESIDialect.h:56
constexpr StringRef extModPortReadySuffix
Suffix lowered ready ports with this suffix.
Definition: ESIDialect.h:53
constexpr StringRef extModBundleSignalsAttrName
Name of dialect attribute which governs whether or not to bundle (i.e.
Definition: ESIDialect.h:38
constexpr StringRef extModPortInSuffix
Suffix all lowered input ports with this suffix. Defaults to nothing.
Definition: ESIDialect.h:45
std::unique_ptr< OperationPass< ModuleOp > > createESIPortLoweringPass()
constexpr StringRef extModPortOutSuffix
Suffix all lowered output ports with this suffix. Defaults to nothing.
Definition: ESIDialect.h:47
constexpr StringRef extModPortEmptySuffix
Suffix lowered empty ports with this suffix.
Definition: ESIDialect.h:59
ModuleType fnToMod(Operation *op, ArrayRef< Attribute > inputNames, ArrayRef< Attribute > outputNames)
Definition: HWTypes.cpp:984
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
Definition: esi.py:1
This holds the name, type, direction of a module's ports.