CIRCT 20.0.0git
Loading...
Searching...
No Matches
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
16#include "circt/Support/LLVM.h"
18
19#include "mlir/Transforms/DialectConversion.h"
20
21namespace circt {
22namespace esi {
23#define GEN_PASS_DEF_LOWERESIPORTS
24#include "circt/Dialect/ESI/ESIPasses.h.inc"
25} // namespace esi
26} // namespace circt
27
28using namespace circt;
29using namespace circt::esi;
30using namespace circt::esi::detail;
31using 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'.
35inline 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
43namespace {
44
45// Base class for all ESI signaling standards, which handles potentially funky
46// attribute-based naming conventions.
47struct ESISignalingStandad : public PortConversion {
48 ESISignalingStandad(PortConverterImpl &converter, hw::PortInfo origPort)
49 : PortConversion(converter, origPort) {}
50};
51
52/// Implement the Valid/Ready signaling standard.
53class ValidReady : public ESISignalingStandad {
54public:
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
66private:
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.
76class FIFO : public ESISignalingStandad {
77public:
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
88private:
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
97class ESIPortConversionBuilder : public PortConversionBuilder {
98public:
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)
104 -> FailureOr<std::unique_ptr<PortConversion>> {
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::FIFO)
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
124void 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
159void 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
169void 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
202void 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
213void 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
250void 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
260void 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
292void 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
302namespace {
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.
307struct ESIPortsPass : public circt::esi::impl::LowerESIPortsBase<ESIPortsPass> {
308 void runOnOperation() override;
309
310private:
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.
318void 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.
356bool 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
428static 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.
445static 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.
471void 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
587std::unique_ptr<OperationPass<ModuleOp>>
589 return std::make_unique<ESIPortsPass>();
590}
return wrap(CMemoryType::get(unwrap(ctx), baseType, numElements))
static StringRef getOperandName(Value operand)
static StringRef getStringAttributeOr(Operation *op, StringRef attrName, StringRef def)
static std::string & constructInstanceName(Value operand, sv::InterfaceOp iface, std::string &name)
Create a reasonable name for a SV interface instance.
static InstancePath empty
static EvaluatorValuePtr unwrap(OMEvaluatorValue c)
Definition OM.cpp:113
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.
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:55
constexpr StringRef extModPortValidSuffix
Suffix lowered valid ports with this suffix.
Definition ESIDialect.h:51
constexpr StringRef extModPortRdenSuffix
Suffix lowered read enable ports with this suffix.
Definition ESIDialect.h:57
constexpr StringRef extModPortReadySuffix
Suffix lowered ready ports with this suffix.
Definition ESIDialect.h:54
constexpr StringRef extModBundleSignalsAttrName
Name of dialect attribute which governs whether or not to bundle (i.e.
Definition ESIDialect.h:39
constexpr StringRef extModPortInSuffix
Suffix all lowered input ports with this suffix. Defaults to nothing.
Definition ESIDialect.h:46
std::unique_ptr< OperationPass< ModuleOp > > createESIPortLoweringPass()
constexpr StringRef extModPortOutSuffix
Suffix all lowered output ports with this suffix. Defaults to nothing.
Definition ESIDialect.h:48
constexpr StringRef extModPortEmptySuffix
Suffix lowered empty ports with this suffix.
Definition ESIDialect.h:60
ModuleType fnToMod(Operation *op, ArrayRef< Attribute > inputNames, ArrayRef< Attribute > outputNames)
Definition HWTypes.cpp:1023
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition esi.py:1
int run(Type[Generator] generator=CppGenerator, cmdline_args=sys.argv)
Definition codegen.py:121
mlir::Type type
Definition HWTypes.h:31
This holds the name, type, direction of a module's ports.