21#include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h"
22#include "mlir/Dialect/Arith/IR/Arith.h"
23#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
24#include "mlir/Dialect/ControlFlow/Transforms/StructuralTypeConversions.h"
25#include "mlir/Dialect/Func/IR/FuncOps.h"
26#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
27#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
28#include "mlir/Dialect/Math/IR/Math.h"
29#include "mlir/Dialect/SCF/IR/SCF.h"
30#include "mlir/IR/BuiltinDialect.h"
31#include "mlir/IR/Iterators.h"
32#include "mlir/Interfaces/SideEffectInterfaces.h"
33#include "mlir/Pass/Pass.h"
34#include "mlir/Transforms/DialectConversion.h"
35#include "mlir/Transforms/RegionUtils.h"
36#include "llvm/ADT/TypeSwitch.h"
37#include "llvm/IR/DerivedTypes.h"
40#define GEN_PASS_DEF_CONVERTMOORETOCORE
41#include "circt/Conversion/Passes.h.inc"
48using comb::ICmpPredicate;
49using llvm::SmallDenseSet;
54struct ClassTypeCache {
55 struct ClassStructInfo {
56 LLVM::LLVMStructType classBody;
59 DenseMap<StringRef, SmallVector<unsigned, 2>> propertyPath;
63 void setFieldPath(StringRef propertyName, ArrayRef<unsigned> path) {
64 this->propertyPath[propertyName] =
65 SmallVector<unsigned, 2>(path.begin(), path.end());
69 std::optional<ArrayRef<unsigned>>
70 getFieldPath(StringRef propertySym)
const {
71 if (
auto prop = this->propertyPath.find(propertySym);
72 prop != this->propertyPath.end())
73 return ArrayRef<unsigned>(prop->second);
80 void setClassInfo(SymbolRefAttr classSym,
const ClassStructInfo &
info) {
81 auto &dst = classToStructMap[classSym];
86 std::optional<ClassStructInfo> getStructInfo(SymbolRefAttr classSym)
const {
87 if (
auto it = classToStructMap.find(classSym); it != classToStructMap.end())
96 DenseMap<Attribute, ClassStructInfo> classToStructMap;
100static LLVM::LLVMFuncOp getOrCreateMalloc(ModuleOp mod, OpBuilder &b) {
101 if (
auto f = mod.lookupSymbol<LLVM::LLVMFuncOp>(
"malloc"))
104 OpBuilder::InsertionGuard g(b);
105 b.setInsertionPointToStart(mod.getBody());
107 auto i64Ty = IntegerType::get(mod.getContext(), 64);
108 auto ptrTy = LLVM::LLVMPointerType::get(mod.getContext());
109 auto fnTy = LLVM::LLVMFunctionType::get(ptrTy, {i64Ty},
false);
111 auto fn = LLVM::LLVMFuncOp::create(b, mod.getLoc(),
"malloc", fnTy);
113 fn.setLinkage(LLVM::Linkage::External);
119static LLVM::LLVMStructType getOrCreateOpaqueStruct(MLIRContext *ctx,
120 SymbolRefAttr className) {
121 return LLVM::LLVMStructType::getIdentified(ctx, className.getRootReference());
124static LogicalResult resolveClassStructBody(ClassDeclOp op,
125 TypeConverter
const &typeConverter,
126 ClassTypeCache &cache) {
128 auto classSym = SymbolRefAttr::get(op.getSymNameAttr());
129 auto structInfo = cache.getStructInfo(classSym);
135 ClassTypeCache::ClassStructInfo structBody;
136 SmallVector<Type> structBodyMembers;
139 unsigned derivedStartIdx = 0;
141 if (
auto baseClass = op.getBaseAttr()) {
143 ModuleOp mod = op->getParentOfType<ModuleOp>();
144 auto *opSym = mod.lookupSymbol(baseClass);
145 auto classDeclOp = cast<ClassDeclOp>(opSym);
147 if (failed(resolveClassStructBody(classDeclOp, typeConverter, cache)))
151 auto baseClassStruct = cache.getStructInfo(baseClass);
152 structBodyMembers.push_back(baseClassStruct->classBody);
156 for (
auto &kv : baseClassStruct->propertyPath) {
157 SmallVector<unsigned, 2> path;
159 path.append(kv.second.begin(), kv.second.end());
160 structBody.setFieldPath(kv.first, path);
165 unsigned iterator = derivedStartIdx;
166 auto &block = op.getBody().front();
167 for (Operation &child : block) {
168 if (
auto prop = dyn_cast<ClassPropertyDeclOp>(child)) {
169 Type mooreTy = prop.getPropertyType();
170 Type llvmTy = typeConverter.convertType(mooreTy);
172 return prop.emitOpError()
173 <<
"failed to convert property type " << mooreTy;
175 structBodyMembers.push_back(llvmTy);
178 SmallVector<unsigned, 2> path{iterator};
179 structBody.setFieldPath(prop.getSymName(), path);
185 auto llvmStructTy = getOrCreateOpaqueStruct(op.getContext(), classSym);
187 if (!structBodyMembers.empty() &&
188 failed(llvmStructTy.setBody(structBodyMembers,
false)))
189 return op.emitOpError() <<
"Failed to set LLVM Struct body";
191 structBody.classBody = llvmStructTy;
192 cache.setClassInfo(classSym, structBody);
198static LogicalResult resolveClassStructBody(ModuleOp mod, SymbolRefAttr op,
199 TypeConverter
const &typeConverter,
200 ClassTypeCache &cache) {
201 auto classDeclOp = cast<ClassDeclOp>(*mod.lookupSymbol(op));
202 return resolveClassStructBody(classDeclOp, typeConverter, cache);
209static Value adjustIntegerWidth(OpBuilder &builder, Value value,
210 uint32_t targetWidth, Location loc) {
211 uint32_t intWidth = value.getType().getIntOrFloatBitWidth();
212 if (intWidth == targetWidth)
215 if (intWidth < targetWidth) {
217 builder, loc, builder.getIntegerType(targetWidth - intWidth), 0);
218 return comb::ConcatOp::create(builder, loc, ValueRange{zeroExt, value});
222 intWidth - targetWidth);
224 builder, loc, builder.getIntegerType(intWidth - targetWidth), 0);
225 Value isZero = comb::ICmpOp::create(builder, loc, comb::ICmpPredicate::eq, hi,
229 builder.getIntegerType(targetWidth), -1);
230 return comb::MuxOp::create(builder, loc, isZero, lo, max,
false);
234static FailureOr<hw::ModulePortInfo>
235getModulePortInfo(
const TypeConverter &typeConverter, SVModuleOp op) {
237 size_t resultNum = 0;
238 auto moduleTy = op.getModuleType();
239 SmallVector<hw::PortInfo> ports;
240 ports.reserve(moduleTy.getNumPorts());
242 for (
auto port : moduleTy.getPorts()) {
243 Type portTy = typeConverter.convertType(port.type);
245 return op.emitOpError(
"port '")
246 << port.name <<
"' has unsupported type " << port.type
247 <<
" that cannot be converted to hardware type";
249 if (port.dir == hw::ModulePort::Direction::Output) {
251 hw::PortInfo({{port.name, portTy, port.dir}, resultNum++, {}}));
259 hw::PortInfo({{port.name, portTy, port.dir}, inputNum++, {}}));
271 using OpConversionPattern::OpConversionPattern;
274 matchAndRewrite(SVModuleOp op, OpAdaptor adaptor,
275 ConversionPatternRewriter &rewriter)
const override {
276 rewriter.setInsertionPoint(op);
279 auto portInfo = getModulePortInfo(*typeConverter, op);
280 if (failed(portInfo))
283 auto hwModuleOp = hw::HWModuleOp::create(rewriter, op.getLoc(),
284 op.getSymNameAttr(), *portInfo);
287 SymbolTable::setSymbolVisibility(hwModuleOp,
288 SymbolTable::getSymbolVisibility(op));
289 rewriter.eraseBlock(hwModuleOp.getBodyBlock());
291 rewriter.convertRegionTypes(&op.getBodyRegion(), *typeConverter)))
293 rewriter.inlineRegionBefore(op.getBodyRegion(), hwModuleOp.getBodyRegion(),
294 hwModuleOp.getBodyRegion().end());
297 rewriter.eraseOp(op);
303 using OpConversionPattern::OpConversionPattern;
306 matchAndRewrite(OutputOp op, OpAdaptor adaptor,
307 ConversionPatternRewriter &rewriter)
const override {
308 rewriter.replaceOpWithNewOp<hw::OutputOp>(op, adaptor.getOperands());
314 using OpConversionPattern::OpConversionPattern;
317 matchAndRewrite(InstanceOp op, OpAdaptor adaptor,
318 ConversionPatternRewriter &rewriter)
const override {
319 auto instName = op.getInstanceNameAttr();
320 auto moduleName = op.getModuleNameAttr();
323 rewriter.setInsertionPoint(op);
324 auto instOp = hw::InstanceOp::create(
325 rewriter, op.getLoc(), op.getResultTypes(), instName, moduleName,
326 op.getInputs(), op.getInputNamesAttr(), op.getOutputNamesAttr(),
327 rewriter.getArrayAttr({}),
nullptr,
331 op.replaceAllUsesWith(instOp.getResults());
332 rewriter.eraseOp(op);
337static void getValuesToObserve(Region *region,
338 function_ref<
void(Value)> setInsertionPoint,
339 const TypeConverter *typeConverter,
340 ConversionPatternRewriter &rewriter,
341 SmallVector<Value> &observeValues) {
342 SmallDenseSet<Value> alreadyObserved;
343 Location loc = region->getLoc();
345 auto probeIfSignal = [&](Value value) -> Value {
346 if (!isa<llhd::RefType>(value.getType()))
348 return llhd::ProbeOp::create(rewriter, loc, value);
351 region->getParentOp()->walk<WalkOrder::PreOrder, ForwardDominanceIterator<>>(
352 [&](Operation *operation) {
353 for (
auto value : operation->getOperands()) {
354 if (isa<BlockArgument>(value))
355 value = rewriter.getRemappedValue(value);
357 if (region->isAncestor(value.getParentRegion()))
359 if (
auto *defOp = value.getDefiningOp();
360 defOp && defOp->hasTrait<OpTrait::ConstantLike>())
362 if (!alreadyObserved.insert(value).second)
365 OpBuilder::InsertionGuard g(rewriter);
366 if (
auto remapped = rewriter.getRemappedValue(value)) {
367 setInsertionPoint(remapped);
368 observeValues.push_back(probeIfSignal(remapped));
370 setInsertionPoint(value);
371 auto type = typeConverter->convertType(value.getType());
372 auto converted = typeConverter->materializeTargetConversion(
373 rewriter, loc, type, value);
374 observeValues.push_back(probeIfSignal(converted));
381 using OpConversionPattern::OpConversionPattern;
384 matchAndRewrite(ProcedureOp op, OpAdaptor adaptor,
385 ConversionPatternRewriter &rewriter)
const override {
387 SmallVector<Value> observedValues;
388 if (op.getKind() == ProcedureKind::AlwaysComb ||
389 op.getKind() == ProcedureKind::AlwaysLatch) {
390 auto setInsertionPoint = [&](Value value) {
391 rewriter.setInsertionPoint(op);
393 getValuesToObserve(&op.getBody(), setInsertionPoint, typeConverter,
394 rewriter, observedValues);
397 auto loc = op.getLoc();
398 if (failed(rewriter.convertRegionTypes(&op.getBody(), *typeConverter)))
403 if (op.getKind() == ProcedureKind::Initial ||
404 op.getKind() == ProcedureKind::Final) {
406 if (op.getKind() == ProcedureKind::Initial)
407 newOp = llhd::ProcessOp::create(rewriter, loc, TypeRange{});
409 newOp = llhd::FinalOp::create(rewriter, loc);
410 auto &body = newOp->getRegion(0);
411 rewriter.inlineRegionBefore(op.getBody(), body, body.end());
413 llvm::make_early_inc_range(body.getOps<ReturnOp>())) {
414 rewriter.setInsertionPoint(returnOp);
415 rewriter.replaceOpWithNewOp<llhd::HaltOp>(returnOp, ValueRange{});
417 rewriter.eraseOp(op);
422 auto newOp = llhd::ProcessOp::create(rewriter, loc, TypeRange{});
427 rewriter.createBlock(&newOp.getBody());
428 auto *block = &op.getBody().front();
429 cf::BranchOp::create(rewriter, loc, block);
430 rewriter.inlineRegionBefore(op.getBody(), newOp.getBody(),
431 newOp.getBody().end());
439 if (op.getKind() == ProcedureKind::AlwaysComb ||
440 op.getKind() == ProcedureKind::AlwaysLatch) {
441 Block *waitBlock = rewriter.createBlock(&newOp.getBody());
442 llhd::WaitOp::create(rewriter, loc, ValueRange{}, Value(), observedValues,
443 ValueRange{}, block);
450 for (
auto returnOp :
llvm::make_early_inc_range(newOp.getOps<ReturnOp>())) {
451 rewriter.setInsertionPoint(returnOp);
452 cf::BranchOp::create(rewriter, loc, block);
453 rewriter.eraseOp(returnOp);
456 rewriter.eraseOp(op);
462 using OpConversionPattern::OpConversionPattern;
465 matchAndRewrite(WaitEventOp op, OpAdaptor adaptor,
466 ConversionPatternRewriter &rewriter)
const override {
500 rewriter.splitBlock(op->getBlock(), ++Block::iterator(op));
506 if (op.getBody().front().empty()) {
509 rewriter.replaceOpWithNewOp<llhd::HaltOp>(op, ValueRange{});
513 auto *waitBlock = rewriter.createBlock(resumeBlock);
514 auto *checkBlock = rewriter.createBlock(resumeBlock);
516 auto loc = op.getLoc();
517 rewriter.setInsertionPoint(op);
518 cf::BranchOp::create(rewriter, loc, waitBlock);
528 SmallVector<Value> valuesBefore;
529 rewriter.setInsertionPointToEnd(waitBlock);
530 auto clonedOp = cast<WaitEventOp>(rewriter.clone(*op));
531 bool allDetectsAreAnyChange =
true;
533 llvm::make_early_inc_range(clonedOp.getOps<DetectEventOp>())) {
534 if (detectOp.getEdge() != Edge::AnyChange || detectOp.getCondition())
535 allDetectsAreAnyChange =
false;
536 valuesBefore.push_back(detectOp.getInput());
537 rewriter.eraseOp(detectOp);
543 SmallVector<Value> observeValues;
544 auto setInsertionPointAfterDef = [&](Value value) {
545 if (
auto *op = value.getDefiningOp())
546 rewriter.setInsertionPointAfter(op);
547 if (
auto arg = dyn_cast<BlockArgument>(value))
548 rewriter.setInsertionPointToStart(value.getParentBlock());
551 getValuesToObserve(&clonedOp.getBody(), setInsertionPointAfterDef,
552 typeConverter, rewriter, observeValues);
557 auto waitOp = llhd::WaitOp::create(rewriter, loc, ValueRange{}, Value(),
558 observeValues, ValueRange{}, checkBlock);
559 rewriter.inlineBlockBefore(&clonedOp.getBody().front(), waitOp);
560 rewriter.eraseOp(clonedOp);
564 SmallVector<DetectEventOp> detectOps(op.getBody().getOps<DetectEventOp>());
565 rewriter.inlineBlockBefore(&op.getBody().front(), checkBlock,
567 rewriter.eraseOp(op);
571 auto computeTrigger = [&](Value before, Value after, Edge edge) -> Value {
572 assert(before.getType() == after.getType() &&
573 "mismatched types after clone op");
574 auto beforeType = cast<IntType>(before.getType());
578 if (beforeType.getWidth() != 1 && edge != Edge::AnyChange) {
579 constexpr int LSB = 0;
581 IntType::get(rewriter.getContext(), 1, beforeType.getDomain());
583 moore::ExtractOp::create(rewriter, loc, beforeType, before, LSB);
584 after = moore::ExtractOp::create(rewriter, loc, beforeType, after, LSB);
587 auto intType = rewriter.getIntegerType(beforeType.getWidth());
588 before = typeConverter->materializeTargetConversion(rewriter, loc,
590 after = typeConverter->materializeTargetConversion(rewriter, loc, intType,
593 if (edge == Edge::AnyChange)
594 return comb::ICmpOp::create(rewriter, loc, ICmpPredicate::ne, before,
597 SmallVector<Value> disjuncts;
600 if (edge == Edge::PosEdge || edge == Edge::BothEdges) {
602 comb::XorOp::create(rewriter, loc, before, trueVal,
true);
604 comb::AndOp::create(rewriter, loc, notOldVal, after,
true);
605 disjuncts.push_back(posedge);
608 if (edge == Edge::NegEdge || edge == Edge::BothEdges) {
610 comb::XorOp::create(rewriter, loc, after, trueVal,
true);
612 comb::AndOp::create(rewriter, loc, before, notCurrVal,
true);
613 disjuncts.push_back(posedge);
616 return rewriter.createOrFold<
comb::OrOp>(loc, disjuncts,
true);
623 SmallVector<Value> triggers;
624 for (
auto [detectOp, before] :
llvm::zip(detectOps, valuesBefore)) {
625 if (!allDetectsAreAnyChange) {
626 if (!isa<IntType>(before.getType()))
627 return detectOp->emitError() <<
"requires int operand";
629 rewriter.setInsertionPoint(detectOp);
631 computeTrigger(before, detectOp.getInput(), detectOp.getEdge());
632 if (detectOp.getCondition()) {
633 auto condition = typeConverter->materializeTargetConversion(
634 rewriter, loc, rewriter.getI1Type(), detectOp.getCondition());
636 comb::AndOp::create(rewriter, loc, trigger, condition,
true);
638 triggers.push_back(trigger);
641 rewriter.eraseOp(detectOp);
644 rewriter.setInsertionPointToEnd(checkBlock);
645 if (triggers.empty()) {
650 cf::BranchOp::create(rewriter, loc, resumeBlock);
656 auto triggered = rewriter.createOrFold<
comb::OrOp>(loc, triggers,
true);
657 cf::CondBranchOp::create(rewriter, loc, triggered, resumeBlock,
666static LogicalResult
convert(WaitDelayOp op, WaitDelayOp::Adaptor adaptor,
667 ConversionPatternRewriter &rewriter) {
669 rewriter.splitBlock(op->getBlock(), ++Block::iterator(op));
670 rewriter.setInsertionPoint(op);
671 rewriter.replaceOpWithNewOp<llhd::WaitOp>(op, ValueRange{},
672 adaptor.getDelay(), ValueRange{},
673 ValueRange{}, resumeBlock);
674 rewriter.setInsertionPointToStart(resumeBlock);
679static LogicalResult
convert(UnreachableOp op, UnreachableOp::Adaptor adaptor,
680 ConversionPatternRewriter &rewriter) {
681 rewriter.replaceOpWithNewOp<llhd::HaltOp>(op, ValueRange{});
690 ConversionPatternRewriter &rewriter) {
692 if (isa<mlir::LLVM::LLVMPointerType>(type))
693 return mlir::LLVM::ZeroOp::create(rewriter, loc, type);
696 if (isa<llhd::TimeType>(type)) {
698 llhd::TimeAttr::get(type.getContext(), 0U, llvm::StringRef(
"ns"), 0, 0);
699 return llhd::ConstantTimeOp::create(rewriter, loc, timeAttr);
703 if (
auto floatType = dyn_cast<FloatType>(type)) {
704 auto floatAttr = rewriter.getFloatAttr(floatType, 0.0);
705 return mlir::arith::ConstantOp::create(rewriter, loc, floatAttr);
709 if (
auto strType = dyn_cast<sim::DynamicStringType>(type))
710 return sim::StringConstantOp::create(rewriter, loc, strType,
"");
713 if (
auto queueType = dyn_cast<sim::QueueType>(type))
714 return sim::QueueEmptyOp::create(rewriter, loc, queueType);
717 int64_t width = hw::getBitWidth(type);
725 return rewriter.createOrFold<
hw::BitcastOp>(loc, type, constZero);
728struct ClassPropertyRefOpConversion
730 ClassPropertyRefOpConversion(TypeConverter &tc, MLIRContext *ctx,
731 ClassTypeCache &cache)
735 matchAndRewrite(circt::moore::ClassPropertyRefOp op, OpAdaptor adaptor,
736 ConversionPatternRewriter &rewriter)
const override {
737 Location loc = op.getLoc();
738 MLIRContext *ctx = rewriter.getContext();
741 Type dstTy = getTypeConverter()->convertType(op.getPropertyRef().getType());
743 Value instRef = adaptor.getInstance();
747 cast<circt::moore::ClassHandleType>(op.getInstance().getType());
748 SymbolRefAttr classSym = classRefTy.getClassSym();
749 ModuleOp mod = op->getParentOfType<ModuleOp>();
750 if (failed(resolveClassStructBody(mod, classSym, *typeConverter, cache)))
751 return rewriter.notifyMatchFailure(op,
752 "Could not resolve class struct for " +
753 classSym.getRootReference().str());
755 auto structInfo = cache.getStructInfo(classSym);
756 assert(structInfo &&
"class struct info must exist");
757 auto structTy = structInfo->classBody;
760 auto propSym = op.getProperty();
761 auto pathOpt = structInfo->getFieldPath(propSym);
763 return rewriter.notifyMatchFailure(op,
764 "no GEP path for property " + propSym);
766 auto i32Ty = IntegerType::get(ctx, 32);
767 SmallVector<Value> idxVals;
768 for (
unsigned idx : *pathOpt)
769 idxVals.push_back(LLVM::ConstantOp::create(
770 rewriter, loc, i32Ty, rewriter.getI32IntegerAttr(idx)));
773 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
775 LLVM::GEPOp::create(rewriter, loc, ptrTy, structTy, instRef, idxVals);
778 Value fieldRef = UnrealizedConversionCastOp::create(rewriter, loc, dstTy,
782 rewriter.replaceOp(op, fieldRef);
787 ClassTypeCache &cache;
791 using OpConversionPattern::OpConversionPattern;
794 matchAndRewrite(ClassUpcastOp op, OpAdaptor adaptor,
795 ConversionPatternRewriter &rewriter)
const override {
797 Type dstTy = getTypeConverter()->convertType(op.getResult().getType());
798 Type srcTy = adaptor.getInstance().getType();
801 return rewriter.notifyMatchFailure(op,
"failed to convert result type");
804 if (dstTy == srcTy && isa<LLVM::LLVMPointerType>(srcTy)) {
805 rewriter.replaceOp(op, adaptor.getInstance());
808 return rewriter.notifyMatchFailure(
809 op,
"Upcast applied to non-opaque pointers!");
815 ClassNewOpConversion(TypeConverter &tc, MLIRContext *ctx,
816 ClassTypeCache &cache)
820 matchAndRewrite(ClassNewOp op, OpAdaptor adaptor,
821 ConversionPatternRewriter &rewriter)
const override {
822 Location loc = op.getLoc();
823 MLIRContext *ctx = rewriter.getContext();
825 auto handleTy = cast<ClassHandleType>(op.getResult().getType());
826 auto sym = handleTy.getClassSym();
828 ModuleOp mod = op->getParentOfType<ModuleOp>();
830 if (failed(resolveClassStructBody(mod, sym, *typeConverter, cache)))
831 return op.emitError() <<
"Could not resolve class struct for " << sym;
833 auto structTy = cache.getStructInfo(sym)->classBody;
837 uint64_t byteSize = dl.getTypeSize(structTy);
838 auto i64Ty = IntegerType::get(ctx, 64);
839 auto cSize = LLVM::ConstantOp::create(rewriter, loc, i64Ty,
840 rewriter.getI64IntegerAttr(byteSize));
843 auto mallocFn = getOrCreateMalloc(mod, rewriter);
844 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
846 LLVM::CallOp::create(rewriter, loc, TypeRange{ptrTy},
847 SymbolRefAttr::get(mallocFn), ValueRange{cSize});
851 rewriter.replaceOp(op, call.getResult());
856 ClassTypeCache &cache;
860 ClassDeclOpConversion(TypeConverter &tc, MLIRContext *ctx,
861 ClassTypeCache &cache)
865 matchAndRewrite(ClassDeclOp op, OpAdaptor,
866 ConversionPatternRewriter &rewriter)
const override {
868 if (failed(resolveClassStructBody(op, *typeConverter, cache)))
871 rewriter.eraseOp(op);
876 ClassTypeCache &cache;
880 using OpConversionPattern::OpConversionPattern;
883 matchAndRewrite(VariableOp op, OpAdaptor adaptor,
884 ConversionPatternRewriter &rewriter)
const override {
885 auto loc = op.getLoc();
886 auto resultType = typeConverter->convertType(op.getResult().getType());
888 return rewriter.notifyMatchFailure(op.getLoc(),
"invalid variable type");
891 Value init = adaptor.getInitial();
893 auto elementType = cast<llhd::RefType>(resultType).getNestedType();
899 rewriter.replaceOpWithNewOp<llhd::SignalOp>(op, resultType,
900 op.getNameAttr(), init);
906 using OpConversionPattern::OpConversionPattern;
909 matchAndRewrite(NetOp op, OpAdaptor adaptor,
910 ConversionPatternRewriter &rewriter)
const override {
911 auto loc = op.getLoc();
913 auto resultType = typeConverter->convertType(op.getResult().getType());
915 return rewriter.notifyMatchFailure(loc,
"invalid net type");
917 auto elementType = cast<llhd::RefType>(resultType).getNestedType();
923 createInitialValue(op.getKind(), rewriter, loc, width,
elementType);
924 auto signal = rewriter.replaceOpWithNewOp<llhd::SignalOp>(
925 op, resultType, op.getNameAttr(), init);
927 if (
auto assignedValue = adaptor.getAssignment()) {
928 auto timeAttr = llhd::TimeAttr::get(resultType.getContext(), 0U,
929 llvm::StringRef(
"ns"), 0, 1);
930 auto time = llhd::ConstantTimeOp::create(rewriter, loc, timeAttr);
931 llhd::DriveOp::create(rewriter, loc, signal, assignedValue, time,
938 static mlir::Value createInitialValue(NetKind kind,
939 ConversionPatternRewriter &rewriter,
940 Location loc, int64_t width,
951 if (kind == NetKind::Supply1 || kind == NetKind::Tri1)
952 return APInt::getAllOnes(width);
953 return APInt::getZero(width);
961static LogicalResult
convert(GlobalVariableOp op,
962 GlobalVariableOp::Adaptor adaptor,
963 ConversionPatternRewriter &rewriter,
964 const TypeConverter &typeConverter) {
965 auto type = typeConverter.convertType(op.getType());
966 auto sig = llhd::GlobalSignalOp::create(rewriter, op.getLoc(),
967 op.getSymNameAttr(), type);
968 sig.getInitRegion().takeBody(op.getInitRegion());
969 rewriter.eraseOp(op);
974static LogicalResult
convert(GetGlobalVariableOp op,
975 GetGlobalVariableOp::Adaptor adaptor,
976 ConversionPatternRewriter &rewriter,
977 const TypeConverter &typeConverter) {
978 auto type = typeConverter.convertType(op.getType());
979 rewriter.replaceOpWithNewOp<llhd::GetGlobalSignalOp>(op, type,
980 op.getGlobalNameAttr());
989 using OpConversionPattern::OpConversionPattern;
992 matchAndRewrite(ConstantOp op, OpAdaptor adaptor,
993 ConversionPatternRewriter &rewriter)
const override {
995 auto value = op.getValue().toAPInt(
false);
996 auto type = rewriter.getIntegerType(value.getBitWidth());
998 op, type, rewriter.getIntegerAttr(type, value));
1004 using OpConversionPattern::OpConversionPattern;
1007 matchAndRewrite(ConstantRealOp op, OpAdaptor adaptor,
1008 ConversionPatternRewriter &rewriter)
const override {
1009 rewriter.replaceOpWithNewOp<arith::ConstantOp>(op, op.getValueAttr());
1015 using OpConversionPattern::OpConversionPattern;
1018 matchAndRewrite(ConstantTimeOp op, OpAdaptor adaptor,
1019 ConversionPatternRewriter &rewriter)
const override {
1020 rewriter.replaceOpWithNewOp<llhd::ConstantTimeOp>(
1021 op, llhd::TimeAttr::get(op->getContext(), op.getValue(),
1022 StringRef(
"fs"), 0, 0));
1028 using OpConversionPattern::OpConversionPattern;
1030 matchAndRewrite(moore::ConstantStringOp op, OpAdaptor adaptor,
1031 ConversionPatternRewriter &rewriter)
const override {
1032 const auto resultType =
1033 typeConverter->convertType(op.getResult().getType());
1034 const auto intType = mlir::cast<IntegerType>(resultType);
1036 const auto str = op.getValue();
1037 const unsigned byteWidth = intType.getWidth();
1038 APInt value(byteWidth, 0);
1041 const size_t maxChars =
1042 std::min(str.size(),
static_cast<size_t>(byteWidth / 8));
1043 for (
size_t i = 0; i < maxChars; i++) {
1044 const size_t pos = str.size() - 1 - i;
1045 const auto asciiChar =
static_cast<uint8_t
>(str[pos]);
1046 value |= APInt(byteWidth, asciiChar) << (8 * i);
1050 op, resultType, rewriter.getIntegerAttr(resultType, value));
1056 using OpConversionPattern::OpConversionPattern;
1058 matchAndRewrite(ConcatOp op, OpAdaptor adaptor,
1059 ConversionPatternRewriter &rewriter)
const override {
1060 rewriter.replaceOpWithNewOp<
comb::ConcatOp>(op, adaptor.getValues());
1066 using OpConversionPattern::OpConversionPattern;
1068 matchAndRewrite(ReplicateOp op, OpAdaptor adaptor,
1069 ConversionPatternRewriter &rewriter)
const override {
1070 Type resultType = typeConverter->convertType(op.getResult().getType());
1072 rewriter.replaceOpWithNewOp<comb::ReplicateOp>(op, resultType,
1073 adaptor.getValue());
1079 using OpConversionPattern::OpConversionPattern;
1082 matchAndRewrite(ExtractOp op, OpAdaptor adaptor,
1083 ConversionPatternRewriter &rewriter)
const override {
1086 Type resultType = typeConverter->convertType(op.getResult().getType());
1087 Type inputType = adaptor.getInput().getType();
1088 int32_t low = adaptor.getLowBit();
1090 if (isa<IntegerType>(inputType)) {
1091 int32_t inputWidth = inputType.getIntOrFloatBitWidth();
1092 int32_t resultWidth = hw::getBitWidth(resultType);
1093 int32_t high = low + resultWidth;
1095 SmallVector<Value> toConcat;
1098 rewriter, op.getLoc(), APInt(std::min(-low, resultWidth), 0)));
1100 if (low < inputWidth && high > 0) {
1101 int32_t lowIdx = std::max(low, 0);
1104 rewriter.getIntegerType(
1105 std::min(resultWidth, std::min(high, inputWidth) - lowIdx)),
1106 adaptor.getInput(), lowIdx);
1107 toConcat.push_back(middle);
1110 int32_t diff = high - inputWidth;
1114 toConcat.push_back(val);
1119 rewriter.replaceOp(op, concat);
1123 if (
auto arrTy = dyn_cast<hw::ArrayType>(inputType)) {
1124 int32_t width = llvm::Log2_64_Ceil(arrTy.getNumElements());
1125 int32_t inputWidth = arrTy.getNumElements();
1127 if (
auto resArrTy = dyn_cast<hw::ArrayType>(resultType);
1128 resArrTy && resArrTy != arrTy.getElementType()) {
1129 int32_t elementWidth = hw::getBitWidth(arrTy.getElementType());
1130 if (elementWidth < 0)
1133 int32_t high = low + resArrTy.getNumElements();
1134 int32_t resWidth = resArrTy.getNumElements();
1136 SmallVector<Value> toConcat;
1139 rewriter, op.getLoc(),
1140 APInt(std::min((-low) * elementWidth, resWidth * elementWidth),
1143 op.getLoc(), hw::ArrayType::get(arrTy.getElementType(), -low),
1145 toConcat.push_back(res);
1148 if (low < inputWidth && high > 0) {
1149 int32_t lowIdx = std::max(0, low);
1151 rewriter, op.getLoc(), rewriter.getIntegerType(width), lowIdx);
1155 arrTy.getElementType(),
1156 std::min(resWidth, std::min(inputWidth, high) - lowIdx)),
1157 adaptor.getInput(), lowIdxVal);
1158 toConcat.push_back(middle);
1161 int32_t diff = high - inputWidth;
1164 rewriter, op.getLoc(), APInt(diff * elementWidth, 0));
1166 rewriter, op.getLoc(),
1167 hw::ArrayType::get(arrTy.getElementType(), diff), constZero);
1168 toConcat.push_back(val);
1173 rewriter.replaceOp(op, concat);
1178 if (low < 0 || low >= inputWidth) {
1179 int32_t bw = hw::getBitWidth(resultType);
1185 rewriter.createOrFold<
hw::BitcastOp>(op.getLoc(), resultType, val);
1186 rewriter.replaceOp(op, bitcast);
1191 rewriter.getIntegerType(width),
1192 adaptor.getLowBit());
1193 rewriter.replaceOpWithNewOp<
hw::ArrayGetOp>(op, adaptor.getInput(), idx);
1202 using OpConversionPattern::OpConversionPattern;
1205 matchAndRewrite(ExtractRefOp op, OpAdaptor adaptor,
1206 ConversionPatternRewriter &rewriter)
const override {
1208 Type resultType = typeConverter->convertType(op.getResult().getType());
1210 cast<llhd::RefType>(adaptor.getInput().getType()).getNestedType();
1212 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1213 int64_t width = hw::getBitWidth(inputType);
1218 rewriter, op.getLoc(),
1219 rewriter.getIntegerType(llvm::Log2_64_Ceil(width)),
1220 adaptor.getLowBit());
1221 rewriter.replaceOpWithNewOp<llhd::SigExtractOp>(
1222 op, resultType, adaptor.getInput(), lowBit);
1226 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1228 rewriter, op.getLoc(),
1229 rewriter.getIntegerType(llvm::Log2_64_Ceil(arrType.getNumElements())),
1230 adaptor.getLowBit());
1234 if (arrType.getElementType() !=
1235 cast<llhd::RefType>(resultType).getNestedType()) {
1236 rewriter.replaceOpWithNewOp<llhd::SigArraySliceOp>(
1237 op, resultType, adaptor.getInput(), lowBit);
1241 rewriter.replaceOpWithNewOp<llhd::SigArrayGetOp>(op, adaptor.getInput(),
1251 using OpConversionPattern::OpConversionPattern;
1254 matchAndRewrite(DynExtractOp op, OpAdaptor adaptor,
1255 ConversionPatternRewriter &rewriter)
const override {
1256 Type resultType = typeConverter->convertType(op.getResult().getType());
1257 Type inputType = adaptor.getInput().getType();
1259 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1260 Value amount = adjustIntegerWidth(rewriter, adaptor.getLowBit(),
1261 intType.getWidth(), op->getLoc());
1262 Value value = comb::ShrUOp::create(rewriter, op->getLoc(),
1263 adaptor.getInput(), amount);
1265 rewriter.replaceOpWithNewOp<
comb::ExtractOp>(op, resultType, value, 0);
1269 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1270 unsigned idxWidth = llvm::Log2_64_Ceil(arrType.getNumElements());
1271 Value idx = adjustIntegerWidth(rewriter, adaptor.getLowBit(), idxWidth,
1274 bool isSingleElementExtract = arrType.getElementType() == resultType;
1276 if (isSingleElementExtract)
1277 rewriter.replaceOpWithNewOp<
hw::ArrayGetOp>(op, adaptor.getInput(),
1281 adaptor.getInput(), idx);
1291 using OpConversionPattern::OpConversionPattern;
1294 matchAndRewrite(DynExtractRefOp op, OpAdaptor adaptor,
1295 ConversionPatternRewriter &rewriter)
const override {
1297 Type resultType = typeConverter->convertType(op.getResult().getType());
1299 cast<llhd::RefType>(adaptor.getInput().getType()).getNestedType();
1301 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1302 int64_t width = hw::getBitWidth(inputType);
1307 adjustIntegerWidth(rewriter, adaptor.getLowBit(),
1308 llvm::Log2_64_Ceil(width), op->getLoc());
1309 rewriter.replaceOpWithNewOp<llhd::SigExtractOp>(
1310 op, resultType, adaptor.getInput(), amount);
1314 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1315 Value idx = adjustIntegerWidth(
1316 rewriter, adaptor.getLowBit(),
1317 llvm::Log2_64_Ceil(arrType.getNumElements()), op->getLoc());
1319 auto resultNestedType = cast<llhd::RefType>(resultType).getNestedType();
1320 bool isSingleElementExtract =
1321 arrType.getElementType() == resultNestedType;
1323 if (isSingleElementExtract)
1324 rewriter.replaceOpWithNewOp<llhd::SigArrayGetOp>(op, adaptor.getInput(),
1327 rewriter.replaceOpWithNewOp<llhd::SigArraySliceOp>(
1328 op, resultType, adaptor.getInput(), idx);
1338 using OpConversionPattern::OpConversionPattern;
1341 matchAndRewrite(ArrayCreateOp op, OpAdaptor adaptor,
1342 ConversionPatternRewriter &rewriter)
const override {
1343 Type resultType = typeConverter->convertType(op.getResult().getType());
1345 adaptor.getElements());
1351 using OpConversionPattern::OpConversionPattern;
1354 matchAndRewrite(StructCreateOp op, OpAdaptor adaptor,
1355 ConversionPatternRewriter &rewriter)
const override {
1356 Type resultType = typeConverter->convertType(op.getResult().getType());
1358 adaptor.getFields());
1364 using OpConversionPattern::OpConversionPattern;
1367 matchAndRewrite(StructExtractOp op, OpAdaptor adaptor,
1368 ConversionPatternRewriter &rewriter)
const override {
1370 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1375struct StructExtractRefOpConversion
1377 using OpConversionPattern::OpConversionPattern;
1380 matchAndRewrite(StructExtractRefOp op, OpAdaptor adaptor,
1381 ConversionPatternRewriter &rewriter)
const override {
1382 rewriter.replaceOpWithNewOp<llhd::SigStructExtractOp>(
1383 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1389 using OpConversionPattern::OpConversionPattern;
1392 matchAndRewrite(UnionCreateOp op, OpAdaptor adaptor,
1393 ConversionPatternRewriter &rewriter)
const override {
1394 Type resultType = typeConverter->convertType(op.getResult().getType());
1395 rewriter.replaceOpWithNewOp<hw::UnionCreateOp>(
1396 op, resultType, adaptor.getFieldNameAttr(), adaptor.getInput());
1402 using OpConversionPattern::OpConversionPattern;
1405 matchAndRewrite(UnionExtractOp op, OpAdaptor adaptor,
1406 ConversionPatternRewriter &rewriter)
const override {
1407 rewriter.replaceOpWithNewOp<hw::UnionExtractOp>(op, adaptor.getInput(),
1408 adaptor.getFieldNameAttr());
1413struct UnionExtractRefOpConversion
1415 using OpConversionPattern::OpConversionPattern;
1418 matchAndRewrite(UnionExtractRefOp op, OpAdaptor adaptor,
1419 ConversionPatternRewriter &rewriter)
const override {
1420 rewriter.replaceOpWithNewOp<llhd::SigStructExtractOp>(
1421 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1427 using OpConversionPattern::OpConversionPattern;
1429 matchAndRewrite(ReduceAndOp op, OpAdaptor adaptor,
1430 ConversionPatternRewriter &rewriter)
const override {
1431 Type resultType = typeConverter->convertType(op.getInput().getType());
1434 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::eq,
1435 adaptor.getInput(), max);
1441 using OpConversionPattern::OpConversionPattern;
1443 matchAndRewrite(ReduceOrOp op, OpAdaptor adaptor,
1444 ConversionPatternRewriter &rewriter)
const override {
1445 Type resultType = typeConverter->convertType(op.getInput().getType());
1448 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1449 adaptor.getInput(), zero);
1455 using OpConversionPattern::OpConversionPattern;
1457 matchAndRewrite(ReduceXorOp op, OpAdaptor adaptor,
1458 ConversionPatternRewriter &rewriter)
const override {
1460 rewriter.replaceOpWithNewOp<
comb::ParityOp>(op, adaptor.getInput());
1466 using OpConversionPattern::OpConversionPattern;
1468 matchAndRewrite(BoolCastOp op, OpAdaptor adaptor,
1469 ConversionPatternRewriter &rewriter)
const override {
1470 Type resultType = typeConverter->convertType(op.getInput().getType());
1471 if (isa_and_nonnull<IntegerType>(resultType)) {
1474 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1475 adaptor.getInput(), zero);
1483 using OpConversionPattern::OpConversionPattern;
1485 matchAndRewrite(NotOp op, OpAdaptor adaptor,
1486 ConversionPatternRewriter &rewriter)
const override {
1488 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1491 rewriter.replaceOpWithNewOp<
comb::XorOp>(op, adaptor.getInput(), max);
1497 using OpConversionPattern::OpConversionPattern;
1499 matchAndRewrite(NegOp op, OpAdaptor adaptor,
1500 ConversionPatternRewriter &rewriter)
const override {
1502 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1505 rewriter.replaceOpWithNewOp<
comb::SubOp>(op, zero, adaptor.getInput());
1511 using OpConversionPattern::OpConversionPattern;
1513 matchAndRewrite(NegRealOp op, OpAdaptor adaptor,
1514 ConversionPatternRewriter &rewriter)
const override {
1515 rewriter.replaceOpWithNewOp<arith::NegFOp>(op, adaptor.getInput());
1520template <
typename SourceOp,
typename TargetOp>
1523 using OpAdaptor =
typename SourceOp::Adaptor;
1526 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1527 ConversionPatternRewriter &rewriter)
const override {
1528 rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(),
1529 adaptor.getRhs(),
false);
1534template <
typename SourceOp,
typename TargetOp>
1537 using OpAdaptor =
typename SourceOp::Adaptor;
1540 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1541 ConversionPatternRewriter &rewriter)
const override {
1542 rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(),
1548template <
typename SourceOp, ICmpPredicate pred>
1551 using OpAdaptor =
typename SourceOp::Adaptor;
1554 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1555 ConversionPatternRewriter &rewriter)
const override {
1557 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1559 rewriter.replaceOpWithNewOp<comb::ICmpOp>(
1560 op, resultType, pred, adaptor.getLhs(), adaptor.getRhs());
1565template <
typename SourceOp, arith::CmpFPredicate pred>
1568 using OpAdaptor =
typename SourceOp::Adaptor;
1571 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1572 ConversionPatternRewriter &rewriter)
const override {
1574 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1576 rewriter.replaceOpWithNewOp<arith::CmpFOp>(
1577 op, resultType, pred, adaptor.getLhs(), adaptor.getRhs());
1582template <
typename SourceOp,
bool withoutX>
1585 using OpAdaptor =
typename SourceOp::Adaptor;
1588 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1589 ConversionPatternRewriter &rewriter)
const override {
1595 unsigned bitWidth = op.getLhs().getType().getWidth();
1596 auto ignoredBits = APInt::getZero(bitWidth);
1597 auto detectIgnoredBits = [&](Value value) {
1598 auto constOp = value.getDefiningOp<ConstantOp>();
1601 auto constValue = constOp.getValue();
1603 ignoredBits |= constValue.getZBits();
1605 ignoredBits |= constValue.getUnknownBits();
1607 detectIgnoredBits(op.getLhs());
1608 detectIgnoredBits(op.getRhs());
1612 Value lhs = adaptor.getLhs();
1613 Value rhs = adaptor.getRhs();
1614 if (!ignoredBits.isZero()) {
1615 ignoredBits.flipAllBits();
1617 lhs = rewriter.createOrFold<
comb::AndOp>(op.getLoc(), lhs, maskOp);
1618 rhs = rewriter.createOrFold<
comb::AndOp>(op.getLoc(), rhs, maskOp);
1621 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, ICmpPredicate::ceq, lhs, rhs);
1631 using OpConversionPattern::OpConversionPattern;
1634 matchAndRewrite(ConversionOp op, OpAdaptor adaptor,
1635 ConversionPatternRewriter &rewriter)
const override {
1636 Location loc = op.getLoc();
1637 Type resultType = typeConverter->convertType(op.getResult().getType());
1639 op.emitError(
"conversion result type is not currently supported");
1642 int64_t inputBw = hw::getBitWidth(adaptor.getInput().getType());
1643 int64_t resultBw = hw::getBitWidth(resultType);
1644 if (inputBw == -1 || resultBw == -1)
1648 loc, rewriter.getIntegerType(inputBw), adaptor.getInput());
1649 Value amount = adjustIntegerWidth(rewriter, input, resultBw, loc);
1652 rewriter.createOrFold<
hw::BitcastOp>(loc, resultType, amount);
1653 rewriter.replaceOp(op, result);
1658template <
typename SourceOp>
1661 using OpAdaptor =
typename SourceOp::Adaptor;
1662 using ConversionPattern::typeConverter;
1665 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1666 ConversionPatternRewriter &rewriter)
const override {
1667 auto type = typeConverter->convertType(op.getResult().getType());
1668 if (type == adaptor.getInput().getType())
1669 rewriter.replaceOp(op, adaptor.getInput());
1671 rewriter.replaceOpWithNewOp<
hw::BitcastOp>(op, type, adaptor.getInput());
1677template <
typename SourceOp>
1680 using OpAdaptor =
typename SourceOp::Adaptor;
1681 using ConversionPattern::typeConverter;
1684 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1685 ConversionPatternRewriter &rewriter)
const override {
1686 rewriter.replaceOp(op, adaptor.getInput());
1692 using OpConversionPattern::OpConversionPattern;
1695 matchAndRewrite(TruncOp op, OpAdaptor adaptor,
1696 ConversionPatternRewriter &rewriter)
const override {
1697 rewriter.replaceOpWithNewOp<
comb::ExtractOp>(op, adaptor.getInput(), 0,
1698 op.getType().getWidth());
1704 using OpConversionPattern::OpConversionPattern;
1707 matchAndRewrite(ZExtOp op, OpAdaptor adaptor,
1708 ConversionPatternRewriter &rewriter)
const override {
1709 auto targetWidth = op.getType().getWidth();
1710 auto inputWidth = op.getInput().getType().getWidth();
1713 rewriter, op.getLoc(),
1714 rewriter.getIntegerType(targetWidth - inputWidth), 0);
1717 op, ValueRange{zeroExt, adaptor.getInput()});
1723 using OpConversionPattern::OpConversionPattern;
1726 matchAndRewrite(SExtOp op, OpAdaptor adaptor,
1727 ConversionPatternRewriter &rewriter)
const override {
1728 auto type = typeConverter->convertType(op.getType());
1730 comb::createOrFoldSExt(op.getLoc(), adaptor.getInput(), type, rewriter);
1731 rewriter.replaceOp(op, value);
1737 using OpConversionPattern::OpConversionPattern;
1740 matchAndRewrite(SIntToRealOp op, OpAdaptor adaptor,
1741 ConversionPatternRewriter &rewriter)
const override {
1742 rewriter.replaceOpWithNewOp<arith::SIToFPOp>(
1743 op, typeConverter->convertType(op.getType()), adaptor.getInput());
1749 using OpConversionPattern::OpConversionPattern;
1752 matchAndRewrite(UIntToRealOp op, OpAdaptor adaptor,
1753 ConversionPatternRewriter &rewriter)
const override {
1754 rewriter.replaceOpWithNewOp<arith::UIToFPOp>(
1755 op, typeConverter->convertType(op.getType()), adaptor.getInput());
1761 using OpConversionPattern::OpConversionPattern;
1764 matchAndRewrite(IntToStringOp op, OpAdaptor adaptor,
1765 ConversionPatternRewriter &rewriter)
const override {
1766 rewriter.replaceOpWithNewOp<sim::IntToStringOp>(op, adaptor.getInput());
1772 using OpConversionPattern::OpConversionPattern;
1775 matchAndRewrite(RealToIntOp op, OpAdaptor adaptor,
1776 ConversionPatternRewriter &rewriter)
const override {
1777 rewriter.replaceOpWithNewOp<arith::FPToSIOp>(
1778 op, typeConverter->convertType(op.getType()), adaptor.getInput());
1788 using OpConversionPattern::OpConversionPattern;
1791 matchAndRewrite(hw::InstanceOp op, OpAdaptor adaptor,
1792 ConversionPatternRewriter &rewriter)
const override {
1793 SmallVector<Type> convResTypes;
1794 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
1797 rewriter.replaceOpWithNewOp<hw::InstanceOp>(
1798 op, convResTypes, op.getInstanceName(), op.getModuleName(),
1799 adaptor.getOperands(), op.getArgNames(),
1800 op.getResultNames(),
1801 rewriter.getArrayAttr({}),
nullptr);
1808 using OpConversionPattern::OpConversionPattern;
1811 matchAndRewrite(func::ReturnOp op, OpAdaptor adaptor,
1812 ConversionPatternRewriter &rewriter)
const override {
1813 rewriter.replaceOpWithNewOp<func::ReturnOp>(op, adaptor.getOperands());
1819 using OpConversionPattern::OpConversionPattern;
1822 matchAndRewrite(func::CallOp op, OpAdaptor adaptor,
1823 ConversionPatternRewriter &rewriter)
const override {
1824 SmallVector<Type> convResTypes;
1825 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
1827 rewriter.replaceOpWithNewOp<func::CallOp>(
1828 op, adaptor.getCallee(), convResTypes, adaptor.getOperands());
1833struct UnrealizedConversionCastConversion
1835 using OpConversionPattern::OpConversionPattern;
1838 matchAndRewrite(UnrealizedConversionCastOp op, OpAdaptor adaptor,
1839 ConversionPatternRewriter &rewriter)
const override {
1840 SmallVector<Type> convResTypes;
1841 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
1846 if (convResTypes == adaptor.getOperands().getTypes()) {
1847 rewriter.replaceOp(op, adaptor.getOperands());
1851 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
1852 op, convResTypes, adaptor.getOperands());
1858 using OpConversionPattern::OpConversionPattern;
1861 matchAndRewrite(ShlOp op, OpAdaptor adaptor,
1862 ConversionPatternRewriter &rewriter)
const override {
1863 Type resultType = typeConverter->convertType(op.getResult().getType());
1867 adjustIntegerWidth(rewriter, adaptor.getAmount(),
1868 resultType.getIntOrFloatBitWidth(), op->getLoc());
1869 rewriter.replaceOpWithNewOp<
comb::ShlOp>(op, resultType, adaptor.getValue(),
1876 using OpConversionPattern::OpConversionPattern;
1879 matchAndRewrite(ShrOp op, OpAdaptor adaptor,
1880 ConversionPatternRewriter &rewriter)
const override {
1881 Type resultType = typeConverter->convertType(op.getResult().getType());
1885 adjustIntegerWidth(rewriter, adaptor.getAmount(),
1886 resultType.getIntOrFloatBitWidth(), op->getLoc());
1888 op, resultType, adaptor.getValue(), amount,
false);
1894 using OpConversionPattern::OpConversionPattern;
1897 matchAndRewrite(PowUOp op, OpAdaptor adaptor,
1898 ConversionPatternRewriter &rewriter)
const override {
1899 Type resultType = typeConverter->convertType(op.getResult().getType());
1901 Location loc = op->getLoc();
1906 auto lhs = comb::ConcatOp::create(rewriter, loc, zeroVal, adaptor.getLhs());
1907 auto rhs = comb::ConcatOp::create(rewriter, loc, zeroVal, adaptor.getRhs());
1910 auto pow = mlir::math::IPowIOp::create(rewriter, loc, lhs, rhs);
1918 using OpConversionPattern::OpConversionPattern;
1921 matchAndRewrite(PowSOp op, OpAdaptor adaptor,
1922 ConversionPatternRewriter &rewriter)
const override {
1923 Type resultType = typeConverter->convertType(op.getResult().getType());
1927 rewriter.replaceOpWithNewOp<mlir::math::IPowIOp>(
1928 op, resultType, adaptor.getLhs(), adaptor.getRhs());
1934 using OpConversionPattern::OpConversionPattern;
1937 matchAndRewrite(AShrOp op, OpAdaptor adaptor,
1938 ConversionPatternRewriter &rewriter)
const override {
1939 Type resultType = typeConverter->convertType(op.getResult().getType());
1943 adjustIntegerWidth(rewriter, adaptor.getAmount(),
1944 resultType.getIntOrFloatBitWidth(), op->getLoc());
1946 op, resultType, adaptor.getValue(), amount,
false);
1952 using OpConversionPattern::OpConversionPattern;
1955 matchAndRewrite(ReadOp op, OpAdaptor adaptor,
1956 ConversionPatternRewriter &rewriter)
const override {
1957 rewriter.replaceOpWithNewOp<llhd::ProbeOp>(op, adaptor.getInput());
1962struct AssignedVariableOpConversion
1964 using OpConversionPattern::OpConversionPattern;
1967 matchAndRewrite(AssignedVariableOp op, OpAdaptor adaptor,
1968 ConversionPatternRewriter &rewriter)
const override {
1969 rewriter.replaceOpWithNewOp<hw::WireOp>(op, adaptor.getInput(),
1970 adaptor.getNameAttr());
1976static llhd::TimeAttr
1977getBlockingOrContinuousAssignDelay(mlir::MLIRContext *
context) {
1978 return llhd::TimeAttr::get(
context, 0U,
"ns", 0, 1);
1981template <
typename OpTy>
1984 using OpAdaptor =
typename OpTy::Adaptor;
1987 matchAndRewrite(OpTy op, OpAdaptor adaptor,
1988 ConversionPatternRewriter &rewriter)
const override {
1991 if constexpr (std::is_same_v<OpTy, ContinuousAssignOp> ||
1992 std::is_same_v<OpTy, BlockingAssignOp>) {
1993 delay = llhd::ConstantTimeOp::create(
1994 rewriter, op->getLoc(),
1995 getBlockingOrContinuousAssignDelay(op->getContext()));
1996 }
else if constexpr (std::is_same_v<OpTy, NonBlockingAssignOp>) {
1998 delay = llhd::ConstantTimeOp::create(
1999 rewriter, op->getLoc(),
2000 llhd::TimeAttr::get(op->getContext(), 0U,
"ns", 1, 0));
2003 delay = adaptor.getDelay();
2006 rewriter.replaceOpWithNewOp<llhd::DriveOp>(
2007 op, adaptor.getDst(), adaptor.getSrc(), delay, Value{});
2013 using OpConversionPattern::OpConversionPattern;
2016 matchAndRewrite(ConditionalOp op, OpAdaptor adaptor,
2017 ConversionPatternRewriter &rewriter)
const override {
2022 auto type = typeConverter->convertType(op.getType());
2024 auto hasNoWriteEffect = [](Region ®ion) {
2025 auto result = region.walk([](Operation *operation) {
2026 if (
auto memOp = dyn_cast<MemoryEffectOpInterface>(operation))
2027 if (!memOp.hasEffect<MemoryEffects::Write>() &&
2028 !memOp.hasEffect<MemoryEffects::Free>())
2029 return WalkResult::advance();
2031 if (operation->hasTrait<OpTrait::HasRecursiveMemoryEffects>())
2032 return WalkResult::advance();
2034 return WalkResult::interrupt();
2036 return !result.wasInterrupted();
2039 if (hasNoWriteEffect(op.getTrueRegion()) &&
2040 hasNoWriteEffect(op.getFalseRegion())) {
2041 Operation *trueTerm = op.getTrueRegion().front().getTerminator();
2042 Operation *falseTerm = op.getFalseRegion().front().getTerminator();
2044 rewriter.inlineBlockBefore(&op.getTrueRegion().front(), op);
2045 rewriter.inlineBlockBefore(&op.getFalseRegion().front(), op);
2047 Value convTrueVal = typeConverter->materializeTargetConversion(
2048 rewriter, op.getLoc(), type, trueTerm->getOperand(0));
2049 Value convFalseVal = typeConverter->materializeTargetConversion(
2050 rewriter, op.getLoc(), type, falseTerm->getOperand(0));
2052 rewriter.eraseOp(trueTerm);
2053 rewriter.eraseOp(falseTerm);
2055 rewriter.replaceOpWithNewOp<
comb::MuxOp>(op, adaptor.getCondition(),
2056 convTrueVal, convFalseVal);
2061 scf::IfOp::create(rewriter, op.getLoc(), type, adaptor.getCondition());
2062 rewriter.inlineRegionBefore(op.getTrueRegion(), ifOp.getThenRegion(),
2063 ifOp.getThenRegion().end());
2064 rewriter.inlineRegionBefore(op.getFalseRegion(), ifOp.getElseRegion(),
2065 ifOp.getElseRegion().end());
2066 rewriter.replaceOp(op, ifOp);
2072 using OpConversionPattern::OpConversionPattern;
2075 matchAndRewrite(YieldOp op, OpAdaptor adaptor,
2076 ConversionPatternRewriter &rewriter)
const override {
2077 if (isa<llhd::GlobalSignalOp>(op->getParentOp()))
2078 rewriter.replaceOpWithNewOp<llhd::YieldOp>(op, adaptor.getResult());
2080 rewriter.replaceOpWithNewOp<scf::YieldOp>(op, adaptor.getResult());
2085template <
typename SourceOp>
2088 using OpAdaptor =
typename SourceOp::Adaptor;
2091 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
2092 ConversionPatternRewriter &rewriter)
const override {
2093 rewriter.modifyOpInPlace(op,
2094 [&]() { op->setOperands(adaptor.getOperands()); });
2099template <
typename MooreOpTy,
typename VerifOpTy>
2102 using OpAdaptor =
typename MooreOpTy::Adaptor;
2105 matchAndRewrite(MooreOpTy op, OpAdaptor adaptor,
2106 ConversionPatternRewriter &rewriter)
const override {
2108 op.getLabel().has_value()
2109 ? StringAttr::get(op->getContext(), op.getLabel().value())
2110 : StringAttr::
get(op->getContext());
2111 rewriter.replaceOpWithNewOp<VerifOpTy>(op, adaptor.getCond(), mlir::Value(),
2122 using OpConversionPattern::OpConversionPattern;
2125 matchAndRewrite(FormatLiteralOp op, OpAdaptor adaptor,
2126 ConversionPatternRewriter &rewriter)
const override {
2127 rewriter.replaceOpWithNewOp<sim::FormatLiteralOp>(op, adaptor.getLiteral());
2133 using OpConversionPattern::OpConversionPattern;
2136 matchAndRewrite(FormatConcatOp op, OpAdaptor adaptor,
2137 ConversionPatternRewriter &rewriter)
const override {
2138 rewriter.replaceOpWithNewOp<sim::FormatStringConcatOp>(op,
2139 adaptor.getInputs());
2145 using OpConversionPattern::OpConversionPattern;
2148 matchAndRewrite(FormatIntOp op, OpAdaptor adaptor,
2149 ConversionPatternRewriter &rewriter)
const override {
2151 char padChar = adaptor.getPadding() == IntPadding::Space ? 32 : 48;
2152 IntegerAttr padCharAttr = rewriter.getI8IntegerAttr(padChar);
2153 auto widthAttr = adaptor.getSpecifierWidthAttr();
2155 bool isLeftAligned = adaptor.getAlignment() == IntAlign::Left;
2156 BoolAttr isLeftAlignedAttr = rewriter.getBoolAttr(isLeftAligned);
2158 switch (op.getFormat()) {
2159 case IntFormat::Decimal:
2160 rewriter.replaceOpWithNewOp<sim::FormatDecOp>(
2161 op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr,
2162 adaptor.getIsSignedAttr());
2164 case IntFormat::Binary:
2165 rewriter.replaceOpWithNewOp<sim::FormatBinOp>(
2166 op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr);
2168 case IntFormat::Octal:
2169 rewriter.replaceOpWithNewOp<sim::FormatOctOp>(
2170 op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr);
2172 case IntFormat::HexLower:
2173 rewriter.replaceOpWithNewOp<sim::FormatHexOp>(
2174 op, adaptor.getValue(), rewriter.getBoolAttr(
false),
2175 isLeftAlignedAttr, padCharAttr, widthAttr);
2177 case IntFormat::HexUpper:
2178 rewriter.replaceOpWithNewOp<sim::FormatHexOp>(
2179 op, adaptor.getValue(), rewriter.getBoolAttr(
true), isLeftAlignedAttr,
2180 padCharAttr, widthAttr);
2183 return rewriter.notifyMatchFailure(op,
"unsupported int format");
2188 using OpConversionPattern::OpConversionPattern;
2191 matchAndRewrite(FormatRealOp op, OpAdaptor adaptor,
2192 ConversionPatternRewriter &rewriter)
const override {
2193 auto fracDigitsAttr = adaptor.getFracDigitsAttr();
2195 auto fieldWidthAttr = adaptor.getFieldWidthAttr();
2196 bool isLeftAligned = adaptor.getAlignment() == IntAlign::Left;
2197 mlir::BoolAttr isLeftAlignedAttr = rewriter.getBoolAttr(isLeftAligned);
2199 switch (op.getFormat()) {
2200 case RealFormat::General:
2201 rewriter.replaceOpWithNewOp<sim::FormatGeneralOp>(
2202 op, adaptor.getValue(), isLeftAlignedAttr, fieldWidthAttr,
2205 case RealFormat::Float:
2206 rewriter.replaceOpWithNewOp<sim::FormatFloatOp>(
2207 op, adaptor.getValue(), isLeftAlignedAttr, fieldWidthAttr,
2210 case RealFormat::Exponential:
2211 rewriter.replaceOpWithNewOp<sim::FormatScientificOp>(
2212 op, adaptor.getValue(), isLeftAlignedAttr, fieldWidthAttr,
2220 using OpConversionPattern::OpConversionPattern;
2223 matchAndRewrite(StringLenOp op, OpAdaptor adaptor,
2224 ConversionPatternRewriter &rewriter)
const override {
2225 rewriter.replaceOpWithNewOp<sim::StringLengthOp>(op, adaptor.getStr());
2231 using OpConversionPattern::OpConversionPattern;
2234 matchAndRewrite(StringConcatOp op, OpAdaptor adaptor,
2235 ConversionPatternRewriter &rewriter)
const override {
2236 rewriter.replaceOpWithNewOp<sim::StringConcatOp>(op, adaptor.getInputs());
2242 using OpConversionPattern::OpConversionPattern;
2245 matchAndRewrite(QueueSizeBIOp op, OpAdaptor adaptor,
2246 ConversionPatternRewriter &rewriter)
const override {
2248 llhd::ProbeOp::create(rewriter, op->getLoc(), adaptor.getQueue());
2250 rewriter.replaceOpWithNewOp<sim::QueueSizeOp>(op, readQueue);
2264probeRefAndDriveWithResult(OpBuilder &builder, Location loc, Value ref,
2265 const std::function<Value(Value)> &func) {
2267 Value v = llhd::ProbeOp::create(builder, loc, ref);
2270 Value delay = llhd::ConstantTimeOp::create(
2271 builder, loc, getBlockingOrContinuousAssignDelay(builder.getContext()));
2273 llhd::DriveOp::create(builder, loc, ref, func(v), delay, Value{});
2277 using OpConversionPattern::OpConversionPattern;
2280 matchAndRewrite(QueuePushBackOp op, OpAdaptor adaptor,
2281 ConversionPatternRewriter &rewriter)
const override {
2282 probeRefAndDriveWithResult(
2283 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2284 return sim::QueuePushBackOp::create(rewriter, op->getLoc(), queue,
2285 adaptor.getElement());
2288 rewriter.eraseOp(op);
2293struct QueuePushFrontOpConversion
2295 using OpConversionPattern::OpConversionPattern;
2298 matchAndRewrite(QueuePushFrontOp op, OpAdaptor adaptor,
2299 ConversionPatternRewriter &rewriter)
const override {
2301 probeRefAndDriveWithResult(
2302 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2303 return sim::QueuePushFrontOp::create(rewriter, op->getLoc(), queue,
2304 adaptor.getElement());
2307 rewriter.eraseOp(op);
2313 using OpConversionPattern::OpConversionPattern;
2316 matchAndRewrite(QueuePopBackOp op, OpAdaptor adaptor,
2317 ConversionPatternRewriter &rewriter)
const override {
2318 probeRefAndDriveWithResult(
2319 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2321 sim::QueuePopBackOp::create(rewriter, op->getLoc(), queue);
2323 op.replaceAllUsesWith(popBack.getPopped());
2324 return popBack.getOutQueue();
2326 rewriter.eraseOp(op);
2333 using OpConversionPattern::OpConversionPattern;
2336 matchAndRewrite(QueuePopFrontOp op, OpAdaptor adaptor,
2337 ConversionPatternRewriter &rewriter)
const override {
2338 probeRefAndDriveWithResult(
2339 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2341 sim::QueuePopFrontOp::create(rewriter, op->getLoc(), queue);
2343 op.replaceAllUsesWith(popFront.getPopped());
2344 return popFront.getOutQueue();
2346 rewriter.eraseOp(op);
2353 using OpConversionPattern::OpConversionPattern;
2356 matchAndRewrite(QueueClearOp op, OpAdaptor adaptor,
2357 ConversionPatternRewriter &rewriter)
const override {
2358 auto refType = cast<llhd::RefType>(adaptor.getQueue().getType());
2359 auto queueType = refType.getNestedType();
2361 sim::QueueEmptyOp::create(rewriter, op->getLoc(), queueType);
2364 Value delay = llhd::ConstantTimeOp::create(
2365 rewriter, op.getLoc(),
2366 getBlockingOrContinuousAssignDelay(rewriter.getContext()));
2368 llhd::DriveOp::create(rewriter, op.getLoc(), adaptor.getQueue(), emptyQueue,
2371 rewriter.eraseOp(op);
2377 using OpConversionPattern::OpConversionPattern;
2380 matchAndRewrite(QueueInsertOp op, OpAdaptor adaptor,
2381 ConversionPatternRewriter &rewriter)
const override {
2382 probeRefAndDriveWithResult(
2383 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2385 sim::QueueInsertOp::create(rewriter, op->getLoc(), queue,
2386 adaptor.getIndex(), adaptor.getItem());
2388 return insert.getOutQueue();
2390 rewriter.eraseOp(op);
2397 using OpConversionPattern::OpConversionPattern;
2400 matchAndRewrite(QueueDeleteOp op, OpAdaptor adaptor,
2401 ConversionPatternRewriter &rewriter)
const override {
2402 probeRefAndDriveWithResult(
2403 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2404 auto delOp = sim::QueueDeleteOp::create(rewriter, op->getLoc(), queue,
2405 adaptor.getIndex());
2407 return delOp.getOutQueue();
2409 rewriter.eraseOp(op);
2416 using OpConversionPattern::OpConversionPattern;
2419 matchAndRewrite(DisplayBIOp op, OpAdaptor adaptor,
2420 ConversionPatternRewriter &rewriter)
const override {
2421 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(
2422 op, adaptor.getMessage());
2434static LogicalResult
convert(StopBIOp op, StopBIOp::Adaptor adaptor,
2435 ConversionPatternRewriter &rewriter) {
2436 rewriter.replaceOpWithNewOp<sim::PauseOp>(op,
false);
2441static LogicalResult
convert(FinishBIOp op, FinishBIOp::Adaptor adaptor,
2442 ConversionPatternRewriter &rewriter) {
2443 rewriter.replaceOpWithNewOp<sim::TerminateOp>(op, op.getExitCode() == 0,
2449static LogicalResult
convert(SeverityBIOp op, SeverityBIOp::Adaptor adaptor,
2450 ConversionPatternRewriter &rewriter) {
2452 std::string severityString;
2454 switch (op.getSeverity()) {
2455 case (Severity::Fatal):
2456 severityString =
"Fatal: ";
2458 case (Severity::Error):
2459 severityString =
"Error: ";
2461 case (Severity::Warning):
2462 severityString =
"Warning: ";
2464 case (Severity::Info):
2465 severityString =
"Info: ";
2472 sim::FormatLiteralOp::create(rewriter, op.getLoc(), severityString);
2473 auto message = sim::FormatStringConcatOp::create(
2474 rewriter, op.getLoc(), ValueRange{prefix, adaptor.getMessage()});
2475 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(op, message);
2481 FinishMessageBIOp::Adaptor adaptor,
2482 ConversionPatternRewriter &rewriter) {
2484 rewriter.eraseOp(op);
2493static LogicalResult
convert(TimeBIOp op, TimeBIOp::Adaptor adaptor,
2494 ConversionPatternRewriter &rewriter) {
2495 rewriter.replaceOpWithNewOp<llhd::CurrentTimeOp>(op);
2500static LogicalResult
convert(LogicToTimeOp op, LogicToTimeOp::Adaptor adaptor,
2501 ConversionPatternRewriter &rewriter) {
2502 rewriter.replaceOpWithNewOp<llhd::IntToTimeOp>(op, adaptor.getInput());
2507static LogicalResult
convert(TimeToLogicOp op, TimeToLogicOp::Adaptor adaptor,
2508 ConversionPatternRewriter &rewriter) {
2509 rewriter.replaceOpWithNewOp<llhd::TimeToIntOp>(op, adaptor.getInput());
2518 const TypeConverter &converter) {
2519 target.addIllegalDialect<MooreDialect>();
2520 target.addLegalDialect<comb::CombDialect>();
2521 target.addLegalDialect<hw::HWDialect>();
2522 target.addLegalDialect<seq::SeqDialect>();
2523 target.addLegalDialect<llhd::LLHDDialect>();
2524 target.addLegalDialect<ltl::LTLDialect>();
2525 target.addLegalDialect<mlir::BuiltinDialect>();
2526 target.addLegalDialect<mlir::math::MathDialect>();
2527 target.addLegalDialect<sim::SimDialect>();
2528 target.addLegalDialect<mlir::LLVM::LLVMDialect>();
2529 target.addLegalDialect<verif::VerifDialect>();
2530 target.addLegalDialect<arith::ArithDialect>();
2532 target.addLegalOp<debug::ScopeOp>();
2534 target.addDynamicallyLegalOp<scf::YieldOp, func::CallOp, func::ReturnOp,
2535 UnrealizedConversionCastOp, hw::OutputOp,
2536 hw::InstanceOp, debug::ArrayOp, debug::StructOp,
2538 [&](Operation *op) {
return converter.isLegal(op); });
2540 target.addDynamicallyLegalOp<scf::IfOp, scf::ForOp, scf::ExecuteRegionOp,
2541 scf::WhileOp, scf::ForallOp>([&](Operation *op) {
2542 return converter.isLegal(op) && !op->getParentOfType<llhd::ProcessOp>();
2545 target.addDynamicallyLegalOp<func::FuncOp>([&](func::FuncOp op) {
2546 return converter.isSignatureLegal(op.getFunctionType());
2550 return converter.isSignatureLegal(op.getModuleType().getFuncType()) &&
2551 converter.isLegal(&op.getBody());
2556 typeConverter.addConversion([&](IntType type) {
2557 return IntegerType::get(type.getContext(), type.getWidth());
2560 typeConverter.addConversion([&](RealType type) -> mlir::Type {
2561 MLIRContext *ctx = type.getContext();
2562 switch (type.getWidth()) {
2563 case moore::RealWidth::f32:
2564 return mlir::Float32Type::get(ctx);
2565 case moore::RealWidth::f64:
2566 return mlir::Float64Type::get(ctx);
2570 typeConverter.addConversion(
2571 [&](TimeType type) {
return llhd::TimeType::get(type.getContext()); });
2573 typeConverter.addConversion([&](FormatStringType type) {
2574 return sim::FormatStringType::get(type.getContext());
2577 typeConverter.addConversion([&](StringType type) {
2578 return sim::DynamicStringType::get(type.getContext());
2581 typeConverter.addConversion([&](QueueType type) {
2582 return sim::QueueType::get(type.getContext(),
2583 typeConverter.convertType(type.getElementType()),
2587 typeConverter.addConversion([&](ArrayType type) -> std::optional<Type> {
2588 if (
auto elementType = typeConverter.convertType(type.getElementType()))
2589 return hw::ArrayType::get(
elementType, type.getSize());
2596 typeConverter.addConversion(
2597 [&](UnpackedArrayType type) -> std::optional<Type> {
2598 if (
auto elementType = typeConverter.convertType(type.getElementType()))
2599 return hw::ArrayType::get(
elementType, type.getSize());
2603 typeConverter.addConversion([&](StructType type) -> std::optional<Type> {
2604 SmallVector<hw::StructType::FieldInfo> fields;
2605 for (
auto field : type.getMembers()) {
2606 hw::StructType::FieldInfo info;
2607 info.type = typeConverter.convertType(field.type);
2610 info.name = field.name;
2611 fields.push_back(info);
2613 return hw::StructType::get(type.getContext(), fields);
2621 typeConverter.addConversion(
2622 [&](UnpackedStructType type) -> std::optional<Type> {
2623 SmallVector<hw::StructType::FieldInfo> fields;
2624 for (
auto field : type.getMembers()) {
2625 hw::StructType::FieldInfo info;
2626 info.type = typeConverter.convertType(field.type);
2629 info.name = field.name;
2630 fields.push_back(info);
2632 return hw::StructType::get(type.getContext(), fields);
2636 typeConverter.addConversion([&](UnionType type) -> std::optional<Type> {
2637 SmallVector<hw::UnionType::FieldInfo> fields;
2638 for (
auto field : type.getMembers()) {
2639 hw::UnionType::FieldInfo info;
2640 info.type = typeConverter.convertType(field.type);
2643 info.name = field.name;
2645 fields.push_back(info);
2647 auto result = hw::UnionType::get(type.getContext(), fields);
2652 typeConverter.addConversion(
2653 [&](UnpackedUnionType type) -> std::optional<Type> {
2654 SmallVector<hw::UnionType::FieldInfo> fields;
2655 for (
auto field : type.getMembers()) {
2656 hw::UnionType::FieldInfo info;
2657 info.type = typeConverter.convertType(field.type);
2660 info.name = field.name;
2662 fields.push_back(info);
2664 return hw::UnionType::get(type.getContext(), fields);
2668 typeConverter.addConversion([&](ChandleType type) -> std::optional<Type> {
2669 return LLVM::LLVMPointerType::get(type.getContext());
2673 typeConverter.addConversion(
2674 [](LLVM::LLVMPointerType t) -> std::optional<Type> {
return t; });
2677 typeConverter.addConversion([&](ClassHandleType type) -> std::optional<Type> {
2678 return LLVM::LLVMPointerType::get(type.getContext());
2681 typeConverter.addConversion([&](RefType type) -> std::optional<Type> {
2682 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
2683 return llhd::RefType::get(innerType);
2688 typeConverter.addConversion([](IntegerType type) {
return type; });
2689 typeConverter.addConversion([](FloatType type) {
return type; });
2690 typeConverter.addConversion([](sim::DynamicStringType type) {
return type; });
2691 typeConverter.addConversion([](llhd::TimeType type) {
return type; });
2692 typeConverter.addConversion([](debug::ArrayType type) {
return type; });
2693 typeConverter.addConversion([](debug::ScopeType type) {
return type; });
2694 typeConverter.addConversion([](debug::StructType type) {
return type; });
2696 typeConverter.addConversion([&](llhd::RefType type) -> std::optional<Type> {
2697 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
2698 return llhd::RefType::get(innerType);
2702 typeConverter.addConversion([&](hw::ArrayType type) -> std::optional<Type> {
2703 if (
auto elementType = typeConverter.convertType(type.getElementType()))
2704 return hw::ArrayType::get(
elementType, type.getNumElements());
2708 typeConverter.addConversion([&](hw::StructType type) -> std::optional<Type> {
2709 SmallVector<hw::StructType::FieldInfo> fields;
2710 for (
auto field : type.getElements()) {
2711 hw::StructType::FieldInfo info;
2712 info.type = typeConverter.convertType(field.type);
2715 info.name = field.name;
2716 fields.push_back(info);
2718 return hw::StructType::get(type.getContext(), fields);
2721 typeConverter.addConversion([&](hw::UnionType type) -> std::optional<Type> {
2722 SmallVector<hw::UnionType::FieldInfo> fields;
2723 for (
auto field : type.getElements()) {
2724 hw::UnionType::FieldInfo info;
2725 info.type = typeConverter.convertType(field.type);
2728 info.name = field.name;
2729 info.offset = field.offset;
2730 fields.push_back(info);
2732 return hw::UnionType::get(type.getContext(), fields);
2735 typeConverter.addTargetMaterialization(
2736 [&](mlir::OpBuilder &builder, mlir::Type resultType,
2737 mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
2738 if (inputs.size() != 1 || !inputs[0])
2740 return UnrealizedConversionCastOp::create(builder, loc, resultType,
2745 typeConverter.addSourceMaterialization(
2746 [&](mlir::OpBuilder &builder, mlir::Type resultType,
2747 mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
2748 if (inputs.size() != 1)
2750 return UnrealizedConversionCastOp::create(builder, loc, resultType,
2757 TypeConverter &typeConverter,
2758 ClassTypeCache &classCache) {
2764 patterns.add<ClassPropertyRefOpConversion>(typeConverter,
2765 patterns.getContext(), classCache);
2769 ClassUpcastOpConversion,
2771 VariableOpConversion,
2775 ConversionOpConversion,
2776 BitcastConversion<PackedToSBVOp>,
2777 BitcastConversion<SBVToPackedOp>,
2778 NoOpConversion<LogicToIntOp>,
2779 NoOpConversion<IntToLogicOp>,
2780 NoOpConversion<ToBuiltinIntOp>,
2781 NoOpConversion<FromBuiltinIntOp>,
2785 SIntToRealOpConversion,
2786 UIntToRealOpConversion,
2787 IntToStringOpConversion,
2788 RealToIntOpConversion,
2794 ReplicateOpConversion,
2796 ExtractOpConversion,
2797 DynExtractOpConversion,
2798 DynExtractRefOpConversion,
2800 StructExtractOpConversion,
2801 StructExtractRefOpConversion,
2802 ExtractRefOpConversion,
2803 StructCreateOpConversion,
2804 UnionCreateOpConversion,
2805 UnionExtractOpConversion,
2806 UnionExtractRefOpConversion,
2807 ConditionalOpConversion,
2808 ArrayCreateOpConversion,
2811 ConstantStringOpConv,
2814 ReduceAndOpConversion,
2815 ReduceOrOpConversion,
2816 ReduceXorOpConversion,
2817 BoolCastOpConversion,
2822 BinaryOpConversion<AddOp, comb::AddOp>,
2823 BinaryOpConversion<SubOp, comb::SubOp>,
2824 BinaryOpConversion<MulOp, comb::MulOp>,
2825 BinaryOpConversion<DivUOp, comb::DivUOp>,
2826 BinaryOpConversion<DivSOp, comb::DivSOp>,
2827 BinaryOpConversion<ModUOp, comb::ModUOp>,
2828 BinaryOpConversion<ModSOp, comb::ModSOp>,
2829 BinaryOpConversion<AndOp, comb::AndOp>,
2830 BinaryOpConversion<OrOp, comb::OrOp>,
2831 BinaryOpConversion<XorOp, comb::XorOp>,
2834 NegRealOpConversion,
2837 BinaryRealOpConversion<AddRealOp, arith::AddFOp>,
2838 BinaryRealOpConversion<SubRealOp, arith::SubFOp>,
2839 BinaryRealOpConversion<DivRealOp, arith::DivFOp>,
2840 BinaryRealOpConversion<MulRealOp, arith::MulFOp>,
2841 BinaryRealOpConversion<PowRealOp, math::PowFOp>,
2844 PowUOpConversion, PowSOpConversion,
2847 ICmpOpConversion<UltOp, ICmpPredicate::ult>,
2848 ICmpOpConversion<SltOp, ICmpPredicate::slt>,
2849 ICmpOpConversion<UleOp, ICmpPredicate::ule>,
2850 ICmpOpConversion<SleOp, ICmpPredicate::sle>,
2851 ICmpOpConversion<UgtOp, ICmpPredicate::ugt>,
2852 ICmpOpConversion<SgtOp, ICmpPredicate::sgt>,
2853 ICmpOpConversion<UgeOp, ICmpPredicate::uge>,
2854 ICmpOpConversion<SgeOp, ICmpPredicate::sge>,
2855 ICmpOpConversion<EqOp, ICmpPredicate::eq>,
2856 ICmpOpConversion<NeOp, ICmpPredicate::ne>,
2857 ICmpOpConversion<CaseEqOp, ICmpPredicate::ceq>,
2858 ICmpOpConversion<CaseNeOp, ICmpPredicate::cne>,
2859 ICmpOpConversion<WildcardEqOp, ICmpPredicate::weq>,
2860 ICmpOpConversion<WildcardNeOp, ICmpPredicate::wne>,
2861 FCmpOpConversion<NeRealOp, arith::CmpFPredicate::ONE>,
2862 FCmpOpConversion<FltOp, arith::CmpFPredicate::OLT>,
2863 FCmpOpConversion<FleOp, arith::CmpFPredicate::OLE>,
2864 FCmpOpConversion<FgtOp, arith::CmpFPredicate::OGT>,
2865 FCmpOpConversion<FgeOp, arith::CmpFPredicate::OGE>,
2866 FCmpOpConversion<EqRealOp, arith::CmpFPredicate::OEQ>,
2867 CaseXZEqOpConversion<CaseZEqOp, true>,
2868 CaseXZEqOpConversion<CaseXZEqOp, false>,
2871 SVModuleOpConversion,
2872 InstanceOpConversion,
2873 ProcedureOpConversion,
2874 WaitEventOpConversion,
2882 AssignOpConversion<ContinuousAssignOp>,
2883 AssignOpConversion<DelayedContinuousAssignOp>,
2884 AssignOpConversion<BlockingAssignOp>,
2885 AssignOpConversion<NonBlockingAssignOp>,
2886 AssignOpConversion<DelayedNonBlockingAssignOp>,
2887 AssignedVariableOpConversion,
2890 HWInstanceOpConversion,
2893 UnrealizedConversionCastConversion,
2894 InPlaceOpConversion<debug::ArrayOp>,
2895 InPlaceOpConversion<debug::StructOp>,
2896 InPlaceOpConversion<debug::VariableOp>,
2899 AssertLikeOpConversion<AssertOp, verif::AssertOp>,
2900 AssertLikeOpConversion<AssumeOp, verif::AssumeOp>,
2901 AssertLikeOpConversion<CoverOp, verif::CoverOp>,
2904 FormatLiteralOpConversion,
2905 FormatConcatOpConversion,
2906 FormatIntOpConversion,
2907 FormatRealOpConversion,
2908 DisplayBIOpConversion,
2911 StringLenOpConversion,
2912 StringConcatOpConversion,
2915 QueueSizeBIOpConversion,
2916 QueuePushBackOpConversion,
2917 QueuePushFrontOpConversion,
2918 QueuePopBackOpConversion,
2919 QueuePopFrontOpConversion,
2920 QueueDeleteOpConversion,
2921 QueueInsertOpConversion,
2922 QueueClearOpConversion
2923 >(typeConverter,
patterns.getContext());
2943 mlir::populateAnyFunctionOpInterfaceTypeConversionPattern(
patterns,
2945 hw::populateHWModuleLikeTypeConversionPattern(
2946 hw::HWModuleOp::getOperationName(),
patterns, typeConverter);
2947 populateSCFToControlFlowConversionPatterns(
patterns);
2956struct MooreToCorePass
2957 :
public circt::impl::ConvertMooreToCoreBase<MooreToCorePass> {
2958 void runOnOperation()
override;
2964 return std::make_unique<MooreToCorePass>();
2968void MooreToCorePass::runOnOperation() {
2969 MLIRContext &
context = getContext();
2970 ModuleOp
module = getOperation();
2971 ClassTypeCache classCache;
2973 IRRewriter rewriter(module);
2974 (void)mlir::eraseUnreachableBlocks(rewriter, module->getRegions());
2976 TypeConverter typeConverter;
2979 ConversionTarget target(
context);
2984 mlir::cf::populateCFStructuralTypeConversionsAndLegality(typeConverter,
2987 if (failed(applyFullConversion(module, target, std::move(
patterns))))
2988 signalPassFailure();
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static Value createZeroValue(ImplicitLocOpBuilder &builder, FIRRTLBaseType type, SmallDenseMap< FIRRTLBaseType, Value > &cache)
Construct a zero value of the given type using the given builder.
static LogicalResult convert(StopBIOp op, StopBIOp::Adaptor adaptor, ConversionPatternRewriter &rewriter)
static void populateLegality(ConversionTarget &target, const TypeConverter &converter)
static void populateOpConversion(ConversionPatternSet &patterns, TypeConverter &typeConverter, ClassTypeCache &classCache)
static void populateTypeConversion(TypeConverter &typeConverter)
Extension of RewritePatternSet that allows adding matchAndRewrite functions with op adaptors and Conv...
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void populateArithToCombPatterns(mlir::RewritePatternSet &patterns, TypeConverter &typeConverter)
std::unique_ptr< OperationPass< ModuleOp > > createConvertMooreToCorePass()
Create an Moore to Comb/HW/LLHD conversion pass.
This holds a decoded list of input/inout and output ports for a module or instance.
This holds the name, type, direction of a module's ports.