26#include "mlir/IR/ImplicitLocOpBuilder.h"
27#include "mlir/Pass/Pass.h"
28#include "mlir/Pass/PassManager.h"
29#include "mlir/Transforms/DialectConversion.h"
30#include "llvm/ADT/TypeSwitch.h"
31#include "llvm/Support/MathExtras.h"
36#define GEN_PASS_DEF_DCTOHW
37#include "circt/Conversion/Passes.h.inc"
49 auto *ctx = tuple.getContext();
50 mlir::SmallVector<hw::StructType::FieldInfo, 8> hwfields;
51 for (
auto [i, innerType] : llvm::enumerate(tuple)) {
52 Type convertedInnerType = innerType;
53 if (
auto tupleInnerType = dyn_cast<TupleType>(innerType))
56 {StringAttr::get(ctx,
"field" + Twine(i)), convertedInnerType});
59 return hw::StructType::get(ctx, hwfields);
68 return TypeSwitch<Type, Type>(t)
70 .Case([](hw::StructType st) {
71 llvm::SmallVector<hw::StructType::FieldInfo> structFields(
73 for (
auto &field : structFields)
75 return hw::StructType::get(st.getContext(), structFields);
77 .Case([](NoneType nt) {
return IntegerType::get(nt.getContext(), 0); })
78 .Default([](Type t) {
return t; });
83 llvm::TypeSwitch<Type, Type>(t)
84 .Case([](ValueType vt) {
85 return esi::ChannelType::get(vt.getContext(),
88 .Case([](dc::TokenType tt) {
89 return esi::ChannelType::get(tt.getContext(),
90 IntegerType::get(tt.getContext(), 0));
92 .Default([](
auto t) {
return toHWType(t); });
101struct DCLoweringState {
102 ModuleOp parentModule;
109class ESITypeConverter :
public TypeConverter {
112 addConversion([](Type type) -> Type {
return toESIHWType(type); });
113 addConversion([](esi::ChannelType t) -> Type {
return t; });
114 addTargetMaterialization([](mlir::OpBuilder &builder, mlir::Type resultType,
115 mlir::ValueRange inputs,
116 mlir::Location loc) -> mlir::Value {
117 if (inputs.size() != 1)
120 return UnrealizedConversionCastOp::create(builder, loc, resultType,
125 addSourceMaterialization([](mlir::OpBuilder &builder, mlir::Type resultType,
126 mlir::ValueRange inputs,
127 mlir::Location loc) -> mlir::Value {
128 if (inputs.size() != 1)
131 return UnrealizedConversionCastOp::create(builder, loc, resultType,
148struct InputHandshake {
151 std::optional<Backedge> ready;
157struct OutputHandshake {
159 std::optional<Backedge> valid;
161 std::optional<Backedge> data;
165static void connect(InputHandshake &input, OutputHandshake &output) {
166 output.valid->setValue(input.valid);
167 input.ready->setValue(output.ready);
170template <
typename T,
typename TInner>
171llvm::SmallVector<T> extractValues(llvm::SmallVector<TInner> &container,
172 llvm::function_ref<T(TInner &)> extractor) {
173 llvm::SmallVector<T> result;
174 llvm::transform(container, std::back_inserter(result), extractor);
181 llvm::SmallVector<InputHandshake> inputs;
182 llvm::SmallVector<OutputHandshake> outputs;
184 llvm::SmallVector<Value> getInputValids() {
185 return extractValues<Value, InputHandshake>(
186 inputs, [](
auto &hs) {
return hs.valid; });
188 llvm::SmallVector<std::optional<Backedge>> getInputReadys() {
189 return extractValues<std::optional<Backedge>, InputHandshake>(
190 inputs, [](
auto &hs) {
return hs.ready; });
192 llvm::SmallVector<std::optional<Backedge>> getOutputValids() {
193 return extractValues<std::optional<Backedge>, OutputHandshake>(
194 outputs, [](
auto &hs) {
return hs.valid; });
196 llvm::SmallVector<Value> getInputDatas() {
197 return extractValues<Value, InputHandshake>(
198 inputs, [](
auto &hs) {
return hs.data; });
200 llvm::SmallVector<Value> getOutputReadys() {
201 return extractValues<Value, OutputHandshake>(
202 outputs, [](
auto &hs) {
return hs.ready; });
205 llvm::SmallVector<Value> getOutputChannels() {
206 return extractValues<Value, OutputHandshake>(
207 outputs, [](
auto &hs) {
return hs.channel; });
209 llvm::SmallVector<std::optional<Backedge>> getOutputDatas() {
210 return extractValues<std::optional<Backedge>, OutputHandshake>(
211 outputs, [](
auto &hs) {
return hs.data; });
219 RTLBuilder(Location loc, OpBuilder &builder, Value clk = Value(),
221 : b(builder), loc(loc), clk(clk), rst(rst) {}
223 Value constant(
const APInt &apv, StringRef name = {}) {
226 bool isZeroWidth = apv.getBitWidth() == 0;
228 auto it = constants.find(apv);
229 if (it != constants.end())
235 constants[apv] = cval;
239 Value constant(
unsigned width, int64_t value, StringRef name = {}) {
241 APInt(width, value,
false,
true));
243 std::pair<Value, Value>
wrap(Value data, Value valid, StringRef name = {}) {
244 auto wrapOp = esi::WrapValidReadyOp::create(b, loc, data, valid);
245 return {wrapOp.getResult(0), wrapOp.getResult(1)};
247 std::pair<Value, Value>
unwrap(Value channel, Value ready,
248 StringRef name = {}) {
249 auto unwrapOp = esi::UnwrapValidReadyOp::create(b, loc, channel, ready);
250 return {unwrapOp.getResult(0), unwrapOp.getResult(1)};
254 Value
reg(StringRef name, Value in, Value rstValue, Value clk = Value(),
255 Value rst = Value()) {
256 Value resolvedClk = clk ? clk : this->clk;
257 Value resolvedRst = rst ? rst : this->rst;
259 "No global clock provided to this RTLBuilder - a clock "
260 "signal must be provided to the reg(...) function.");
262 "No global reset provided to this RTLBuilder - a reset "
263 "signal must be provided to the reg(...) function.");
269 Value cmp(Value lhs, Value rhs, comb::ICmpPredicate predicate,
270 StringRef name = {}) {
271 return comb::ICmpOp::create(b, loc, predicate, lhs, rhs);
274 Value buildNamedOp(llvm::function_ref<Value()> f, StringRef name) {
277 Operation *op = v.getDefiningOp();
279 op->setAttr(
"sv.namehint", b.getStringAttr(name));
280 nameAttr = b.getStringAttr(name);
286 Value bitAnd(ValueRange values, StringRef name = {}) {
288 [&]() {
return comb::AndOp::create(b, loc, values,
false); }, name);
292 Value bitOr(ValueRange values, StringRef name = {}) {
294 [&]() {
return comb::OrOp::create(b, loc, values,
false); }, name);
298 Value bitNot(Value value, StringRef name = {}) {
299 auto allOnes = constant(value.getType().getIntOrFloatBitWidth(), -1);
300 std::string inferedName;
304 value.getDefiningOp()->getAttrOfType<StringAttr>(
"sv.namehint")) {
305 inferedName = (
"not_" +
valueName.getValue()).str();
311 [&]() {
return comb::XorOp::create(b, loc, value, allOnes); }, name);
314 Value shl(Value value, Value shift, StringRef name = {}) {
316 [&]() {
return comb::ShlOp::create(b, loc, value, shift); }, name);
319 Value
concat(ValueRange values, StringRef name = {}) {
321 [&]() {
return comb::ConcatOp::create(b, loc, values); }, name);
324 llvm::SmallVector<Value>
extractBits(Value v, StringRef name = {}) {
325 llvm::SmallVector<Value> bits;
326 for (
unsigned i = 0, e = v.getType().getIntOrFloatBitWidth(); i != e; ++i)
332 Value reduceOr(Value v, StringRef name = {}) {
333 return buildNamedOp([&]() {
return bitOr(
extractBits(v)); }, name);
337 Value extract(Value v,
unsigned lo,
unsigned hi, StringRef name = {}) {
338 unsigned width = hi - lo + 1;
344 Value truncate(Value value,
unsigned width, StringRef name = {}) {
345 return extract(value, 0, width - 1, name);
348 Value zext(Value value,
unsigned outWidth, StringRef name = {}) {
349 unsigned inWidth = value.getType().getIntOrFloatBitWidth();
350 assert(inWidth <= outWidth &&
"zext: input width must be <= output width.");
351 if (inWidth == outWidth)
353 auto c0 = constant(outWidth - inWidth, 0);
354 return concat({c0, value}, name);
357 Value sext(Value value,
unsigned outWidth, StringRef name = {}) {
358 return comb::createOrFoldSExt(b, loc, value, b.getIntegerType(outWidth));
362 Value bit(Value v,
unsigned index, StringRef name = {}) {
363 return extract(v, index, index, name);
367 Value arrayCreate(ValueRange values, StringRef name = {}) {
373 Value arrayGet(Value array, Value index, StringRef name = {}) {
381 Value mux(Value index, ValueRange values, StringRef name = {}) {
382 if (values.size() == 2) {
385 return comb::MuxOp::create(b, loc, index, values[1], values[0]);
389 return arrayGet(arrayCreate(values), index, name);
394 Value oneHotMux(Value index, ValueRange inputs) {
396 unsigned numInputs = inputs.size();
397 assert(numInputs == index.getType().getIntOrFloatBitWidth() &&
398 "mismatch between width of one-hot select input and the number of "
399 "inputs to be selected");
402 auto dataType = inputs[0].getType();
404 isa<NoneType>(dataType) ? 0 : dataType.getIntOrFloatBitWidth();
405 Value muxValue = constant(width, 0);
408 for (
size_t i = numInputs - 1; i != 0; --i) {
409 Value input = inputs[i];
410 Value selectBit = bit(index, i);
411 muxValue = mux(selectBit, {muxValue, input});
420 DenseMap<APInt, Value> constants;
423static bool isZeroWidthType(Type type) {
424 if (
auto intType = dyn_cast<IntegerType>(type))
425 return intType.getWidth() == 0;
426 return isa<NoneType>(type);
429static UnwrappedIO unwrapIO(Location loc, ValueRange operands,
431 ConversionPatternRewriter &rewriter,
433 RTLBuilder rtlb(loc, rewriter);
434 UnwrappedIO unwrapped;
435 for (
auto in : operands) {
436 assert(isa<esi::ChannelType>(in.getType()));
437 auto ready = bb.
get(rtlb.b.getI1Type());
438 auto [
data, valid] = rtlb.unwrap(in, ready);
439 unwrapped.inputs.push_back(InputHandshake{in, valid, ready,
data});
441 for (
auto outputType : results) {
447 if (isZeroWidthType(innerType)) {
453 auto dataBackedge = bb.
get(innerType);
454 hs.data = dataBackedge;
457 auto valid = bb.
get(rewriter.getI1Type());
458 auto [dataCh, ready] = rtlb.wrap(data, valid);
462 unwrapped.outputs.push_back(hs);
467static UnwrappedIO unwrapIO(Operation *op, ValueRange operands,
468 ConversionPatternRewriter &rewriter,
470 return unwrapIO(op->getLoc(), operands, op->getResultTypes(), rewriter, bb);
475static FailureOr<std::pair<Value, Value>> getClockAndReset(Operation *op) {
476 auto *parent = op->getParentOp();
477 auto parentFuncOp = dyn_cast<HWModuleLike>(parent);
479 return parent->emitOpError(
"parent op does not implement HWModuleLike");
481 auto argAttrs = parentFuncOp.getAllInputAttrs();
483 std::optional<size_t> clockIdx, resetIdx;
485 for (
auto [idx, battrs] : llvm::enumerate(argAttrs)) {
486 auto attrs = cast<DictionaryAttr>(battrs);
487 if (
attrs.get(
"dc.clock")) {
489 return parent->emitOpError(
490 "multiple arguments contains a 'dc.clock' attribute");
494 if (
attrs.get(
"dc.reset")) {
496 return parent->emitOpError(
497 "multiple arguments contains a 'dc.reset' attribute");
503 return parent->emitOpError(
"no argument contains a 'dc.clock' attribute");
506 return parent->emitOpError(
"no argument contains a 'dc.reset' attribute");
508 return {std::make_pair(parentFuncOp.getArgumentForInput(*clockIdx),
509 parentFuncOp.getArgumentForInput(*resetIdx))};
514 using OpConversionPattern<ForkOp>::OpConversionPattern;
516 matchAndRewrite(ForkOp op, OpAdaptor operands,
517 ConversionPatternRewriter &rewriter)
const override {
518 auto bb = BackedgeBuilder(rewriter, op.getLoc());
519 auto crRes = getClockAndReset(op);
522 auto [clock, reset] = *crRes;
523 RTLBuilder rtlb(op.getLoc(), rewriter, clock, reset);
524 UnwrappedIO io = unwrapIO(op, operands.getOperands(), rewriter, bb);
526 auto &input = io.inputs[0];
528 Value c0I1 = rtlb.constant(1, 0);
529 llvm::SmallVector<Value> doneWires;
530 for (
auto [i, output] : llvm::enumerate(io.outputs)) {
531 Backedge doneBE = bb.
get(rtlb.b.getI1Type());
532 Value emitted = rtlb.bitAnd({doneBE, rtlb.bitNot(*input.ready)});
534 rtlb.reg(
"emitted_" + std::to_string(i), emitted, c0I1);
535 Value outValid = rtlb.bitAnd({rtlb.bitNot(emittedReg), input.valid});
536 output.valid->setValue(outValid);
537 Value validReady = rtlb.bitAnd({output.ready, outValid});
539 rtlb.bitOr({validReady, emittedReg},
"done" + std::to_string(i));
541 doneWires.push_back(done);
543 input.ready->setValue(rtlb.bitAnd(doneWires,
"allDone"));
545 rewriter.replaceOp(op, io.getOutputChannels());
552 using OpConversionPattern<JoinOp>::OpConversionPattern;
555 matchAndRewrite(JoinOp op, OpAdaptor operands,
556 ConversionPatternRewriter &rewriter)
const override {
557 auto bb = BackedgeBuilder(rewriter, op.getLoc());
558 UnwrappedIO io = unwrapIO(op, operands.getOperands(), rewriter, bb);
559 RTLBuilder rtlb(op.getLoc(), rewriter);
560 auto &output = io.outputs[0];
562 Value allValid = rtlb.bitAnd(io.getInputValids());
563 output.valid->setValue(allValid);
565 auto validAndReady = rtlb.bitAnd({output.ready, allValid});
566 for (
auto &input : io.inputs)
567 input.ready->setValue(validAndReady);
569 rewriter.replaceOp(op, io.outputs[0].channel);
576 using OpConversionPattern<SelectOp>::OpConversionPattern;
579 matchAndRewrite(SelectOp op, OpAdaptor operands,
580 ConversionPatternRewriter &rewriter)
const override {
581 auto bb = BackedgeBuilder(rewriter, op.getLoc());
582 UnwrappedIO io = unwrapIO(op, operands.getOperands(), rewriter, bb);
583 RTLBuilder rtlb(op.getLoc(), rewriter);
586 auto select = io.inputs[0];
587 io.inputs.erase(io.inputs.begin());
588 buildMuxLogic(rtlb, io, select);
590 rewriter.replaceOp(op, io.outputs[0].channel);
597 void buildMuxLogic(RTLBuilder &rtlb, UnwrappedIO &unwrapped,
598 InputHandshake &select)
const {
601 size_t numInputs = unwrapped.inputs.size();
602 size_t selectWidth = llvm::Log2_64_Ceil(numInputs);
603 Value truncatedSelect =
604 select.data.getType().getIntOrFloatBitWidth() > selectWidth
605 ? rtlb.truncate(select.data, selectWidth)
609 auto selectZext = rtlb.zext(truncatedSelect, numInputs);
610 auto select1h = rtlb.shl(rtlb.constant(numInputs, 1), selectZext);
611 auto &res = unwrapped.outputs[0];
614 auto selectedInputValid =
615 rtlb.mux(truncatedSelect, unwrapped.getInputValids());
617 auto selAndInputValid = rtlb.bitAnd({selectedInputValid, select.valid});
618 res.valid->setValue(selAndInputValid);
619 auto resValidAndReady = rtlb.bitAnd({selAndInputValid, res.ready});
622 select.ready->setValue(resValidAndReady);
625 for (
auto [inIdx, in] : llvm::enumerate(unwrapped.inputs)) {
627 auto isSelected = rtlb.bit(select1h, inIdx);
631 auto activeAndResultValidAndReady =
632 rtlb.bitAnd({isSelected, resValidAndReady});
633 in.ready->setValue(activeAndResultValidAndReady);
640 using OpConversionPattern::OpConversionPattern;
642 matchAndRewrite(BranchOp op, OpAdaptor operands,
643 ConversionPatternRewriter &rewriter)
const override {
644 auto bb = BackedgeBuilder(rewriter, op.getLoc());
645 UnwrappedIO io = unwrapIO(op, operands.getOperands(), rewriter, bb);
646 RTLBuilder rtlb(op.getLoc(), rewriter);
647 auto cond = io.inputs[0];
648 auto trueRes = io.outputs[0];
649 auto falseRes = io.outputs[1];
652 trueRes.valid->setValue(rtlb.bitAnd({cond.data, cond.valid}));
653 falseRes.valid->setValue(rtlb.bitAnd({rtlb.bitNot(cond.data), cond.valid}));
656 Value selectedResultReady =
657 rtlb.mux(cond.data, {falseRes.ready, trueRes.ready});
658 Value condReady = rtlb.bitAnd({selectedResultReady, cond.valid});
659 cond.ready->setValue(condReady);
661 rewriter.replaceOp(op,
662 SmallVector<Value>{trueRes.channel, falseRes.channel});
669 using OpConversionPattern::OpConversionPattern;
671 matchAndRewrite(MergeOp op, OpAdaptor operands,
672 ConversionPatternRewriter &rewriter)
const override {
673 BackedgeBuilder bb(rewriter, op.getLoc());
674 UnwrappedIO io = unwrapIO(op, operands.getOperands(), rewriter, bb);
675 auto output = io.outputs[0];
676 RTLBuilder rtlb(op.getLoc(), rewriter);
679 Value hasWin = rtlb.bitOr(io.getInputValids());
685 Value winWasFirst = io.inputs[0].valid;
686 Value winWasSecond = rtlb.bitNot(winWasFirst);
687 Value winIndex = winWasSecond;
689 output.valid->setValue(hasWin);
690 output.data->setValue(winIndex);
694 Value outValidAndReady = rtlb.bitAnd({hasWin, output.ready});
698 io.inputs[0].ready->setValue(rtlb.bitAnd({outValidAndReady, winWasFirst}));
699 io.inputs[1].ready->setValue(rtlb.bitAnd({outValidAndReady, winWasSecond}));
701 rewriter.replaceOp(op, output.channel);
711 using OpConversionPattern::OpConversionPattern;
714 matchAndRewrite(ToESIOp op, OpAdaptor operands,
715 ConversionPatternRewriter &rewriter)
const override {
716 rewriter.replaceOp(op, operands.getOperands());
725 using OpConversionPattern::OpConversionPattern;
728 matchAndRewrite(FromESIOp op, OpAdaptor operands,
729 ConversionPatternRewriter &rewriter)
const override {
730 rewriter.replaceOp(op, operands.getOperands());
737 using OpConversionPattern<SinkOp>::OpConversionPattern;
740 matchAndRewrite(SinkOp op, OpAdaptor operands,
741 ConversionPatternRewriter &rewriter)
const override {
742 auto bb = BackedgeBuilder(rewriter, op.getLoc());
743 UnwrappedIO io = unwrapIO(op, operands.getOperands(), rewriter, bb);
744 io.inputs[0].ready->setValue(
745 RTLBuilder(op.getLoc(), rewriter).constant(1, 1));
746 rewriter.eraseOp(op);
753 using OpConversionPattern<SourceOp>::OpConversionPattern;
755 matchAndRewrite(SourceOp op, OpAdaptor operands,
756 ConversionPatternRewriter &rewriter)
const override {
757 auto bb = BackedgeBuilder(rewriter, op.getLoc());
758 UnwrappedIO io = unwrapIO(op, operands.getOperands(), rewriter, bb);
759 RTLBuilder rtlb(op.getLoc(), rewriter);
760 io.outputs[0].valid->setValue(rtlb.constant(1, 1));
761 rewriter.replaceOp(op, io.outputs[0].channel);
768 using OpConversionPattern<PackOp>::OpConversionPattern;
770 matchAndRewrite(PackOp op, OpAdaptor operands,
771 ConversionPatternRewriter &rewriter)
const override {
772 auto bb = BackedgeBuilder(rewriter, op.getLoc());
773 UnwrappedIO io = unwrapIO(op, llvm::SmallVector<Value>{operands.getToken()},
775 RTLBuilder rtlb(op.getLoc(), rewriter);
776 auto &input = io.inputs[0];
777 auto &output = io.outputs[0];
778 output.data->setValue(operands.getInput());
780 rewriter.replaceOp(op, output.channel);
787 using OpConversionPattern<UnpackOp>::OpConversionPattern;
789 matchAndRewrite(UnpackOp op, OpAdaptor operands,
790 ConversionPatternRewriter &rewriter)
const override {
791 auto bb = BackedgeBuilder(rewriter, op.getLoc());
792 UnwrappedIO io = unwrapIO(
793 op.getLoc(), llvm::SmallVector<Value>{operands.getInput()},
795 llvm::SmallVector<Type>{op.getToken().getType()}, rewriter, bb);
796 RTLBuilder rtlb(op.getLoc(), rewriter);
797 auto &input = io.inputs[0];
798 auto &output = io.outputs[0];
800 llvm::SmallVector<Value> unpackedValues;
801 unpackedValues.push_back(input.data);
804 llvm::SmallVector<Value> outputs;
805 outputs.push_back(output.channel);
806 outputs.append(unpackedValues.begin(), unpackedValues.end());
807 rewriter.replaceOp(op, outputs);
814 using OpConversionPattern<BufferOp>::OpConversionPattern;
817 matchAndRewrite(BufferOp op, OpAdaptor operands,
818 ConversionPatternRewriter &rewriter)
const override {
819 if (op.getInitValuesAttr())
820 return rewriter.notifyMatchFailure(
821 op,
"BufferOp with initial values not supported");
823 auto crRes = getClockAndReset(op);
826 auto [clock, reset] = *crRes;
830 Type channelType = operands.getInput().getType();
831 rewriter.replaceOpWithNewOp<esi::ChannelBufferOp>(
832 op, channelType, clock, reset, operands.getInput(), op.getSizeAttr(),
840static bool isDCType(Type type) {
return isa<dc::TokenType, ValueType>(type); }
845 if (
auto funcOp = dyn_cast<HWModuleLike>(op))
846 return llvm::none_of(funcOp.getPortTypes(),
isDCType);
848 bool operandsOK = llvm::none_of(op->getOperandTypes(),
isDCType);
849 bool resultsOK = llvm::none_of(op->getResultTypes(),
isDCType);
850 return operandsOK && resultsOK;
858class DCToHWPass :
public circt::impl::DCToHWBase<DCToHWPass> {
860 void runOnOperation()
override {
861 Operation *parent = getOperation();
865 auto walkRes = parent->walk([&](Operation *op) {
866 for (
auto res : op->getResults()) {
867 if (isa<dc::TokenType, dc::ValueType>(res.getType())) {
868 if (res.use_empty()) {
869 op->emitOpError() <<
"DCToHW: value " << res <<
" is unused.";
870 return WalkResult::interrupt();
872 if (!res.hasOneUse()) {
874 <<
"DCToHW: value " << res <<
" has multiple uses.";
875 return WalkResult::interrupt();
879 return WalkResult::advance();
882 if (walkRes.wasInterrupted()) {
883 parent->emitOpError()
884 <<
"DCToHW: failed to verify that all values "
885 "are used exactly once. Remember to run the "
886 "fork/sink materialization pass before HW lowering.";
891 ESITypeConverter typeConverter;
892 ConversionTarget target(getContext());
893 target.markUnknownOpDynamicallyLegal(
isLegalOp);
897 target.addIllegalDialect<dc::DCDialect>();
899 RewritePatternSet patterns(parent->getContext());
902 ForkConversionPattern, JoinConversionPattern, SelectConversionPattern,
903 BranchConversionPattern, PackConversionPattern, UnpackConversionPattern,
904 BufferConversionPattern, SourceConversionPattern, SinkConversionPattern,
905 MergeConversionPattern, TypeConversionPattern, ToESIConversionPattern,
906 FromESIConversionPattern>(typeConverter, parent->getContext());
908 if (failed(applyPartialConversion(parent, target, std::move(patterns))))
915 return std::make_unique<DCToHWPass>();
assert(baseType &&"element must be base type")
return wrap(CMemoryType::get(unwrap(ctx), baseType, numElements))
static std::string valueName(Operation *scopeOp, Value v)
Convenience function for getting the SSA name of v under the scope of operation scopeOp.
static SmallVector< T > concat(const SmallVectorImpl< T > &a, const SmallVectorImpl< T > &b)
Returns a new vector containing the concatenation of vectors a and b.
static SmallVector< Value > extractBits(OpBuilder &builder, Value val)
static Type toHWType(Type t)
Converts any type 't' into a hw-compatible type.
static bool isDCType(Type type)
static Type tupleToStruct(TupleType tuple)
static bool isLegalOp(Operation *op)
Returns true if the given op is considered as legal - i.e.
std::function< std::string(Operation *)> NameUniquer
static Type toESIHWType(Type t)
false return failure()
Parse an optional keyword or string and set instance into 'result'.
static EvaluatorValuePtr unwrap(OMEvaluatorValue c)
Instantiate one of these and use it to build typed backedges.
Backedge get(mlir::Type resultType, mlir::LocationAttr optionalLoc={})
Create a typed backedge.
void setValue(mlir::Value)
Channels are the basic communication primitives.
const Type * getInner() const
create(elements, Type result_type=None)
create(cls, result_type, reset=None, reset_value=None, name=None, sym_name=None, **kwargs)
connect(destination, source)
mlir::Type innerType(mlir::Type type)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< mlir::Pass > createDCToHWPass()
reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)