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