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++, {}}));
265struct DpiArrayCastInfo {
268 bool isPacked =
false;
272static std::optional<DpiArrayCastInfo> getDpiArrayCastInfo(Type type) {
273 DpiArrayCastInfo
info;
274 if (
auto refType = dyn_cast<RefType>(type)) {
276 type = refType.getNestedType();
279 if (
auto arrayType = dyn_cast<ArrayType>(type)) {
280 info.isPacked =
true;
281 info.elementType = arrayType.getElementType();
284 if (
auto arrayType = dyn_cast<OpenArrayType>(type)) {
286 info.isPacked =
true;
287 info.elementType = arrayType.getElementType();
290 if (
auto arrayType = dyn_cast<UnpackedArrayType>(type)) {
291 info.elementType = arrayType.getElementType();
294 if (
auto arrayType = dyn_cast<OpenUnpackedArrayType>(type)) {
296 info.elementType = arrayType.getElementType();
302static bool hasOpenArrayBoundaryType(Type type) {
303 if (isa<OpenArrayType, OpenUnpackedArrayType>(type))
305 if (
auto refType = dyn_cast<RefType>(type))
306 return isa<OpenArrayType, OpenUnpackedArrayType>(refType.getNestedType());
310static bool isSupportedDpiOpenArrayCast(Type source, Type target) {
311 auto sourceInfo = getDpiArrayCastInfo(source);
312 auto targetInfo = getDpiArrayCastInfo(target);
313 if (!sourceInfo || !targetInfo)
318 return sourceInfo->isRef == targetInfo->isRef &&
319 sourceInfo->isPacked == targetInfo->isPacked &&
320 sourceInfo->elementType == targetInfo->elementType &&
321 (targetInfo->isOpen && !sourceInfo->isOpen);
329 using OpConversionPattern::OpConversionPattern;
332 matchAndRewrite(SVModuleOp op, OpAdaptor adaptor,
333 ConversionPatternRewriter &rewriter)
const override {
334 rewriter.setInsertionPoint(op);
337 auto portInfo = getModulePortInfo(*typeConverter, op);
338 if (failed(portInfo))
341 auto hwModuleOp = hw::HWModuleOp::create(rewriter, op.getLoc(),
342 op.getSymNameAttr(), *portInfo);
345 SymbolTable::setSymbolVisibility(hwModuleOp,
346 SymbolTable::getSymbolVisibility(op));
347 rewriter.eraseBlock(hwModuleOp.getBodyBlock());
349 rewriter.convertRegionTypes(&op.getBodyRegion(), *typeConverter)))
351 rewriter.inlineRegionBefore(op.getBodyRegion(), hwModuleOp.getBodyRegion(),
352 hwModuleOp.getBodyRegion().end());
355 rewriter.eraseOp(op);
361 using OpConversionPattern::OpConversionPattern;
364 matchAndRewrite(OutputOp op, OpAdaptor adaptor,
365 ConversionPatternRewriter &rewriter)
const override {
366 rewriter.replaceOpWithNewOp<hw::OutputOp>(op, adaptor.getOperands());
372 using OpConversionPattern::OpConversionPattern;
375 matchAndRewrite(InstanceOp op, OpAdaptor adaptor,
376 ConversionPatternRewriter &rewriter)
const override {
377 auto instName = op.getInstanceNameAttr();
378 auto moduleName = op.getModuleNameAttr();
381 rewriter.setInsertionPoint(op);
382 auto instOp = hw::InstanceOp::create(
383 rewriter, op.getLoc(), op.getResultTypes(), instName, moduleName,
384 op.getInputs(), op.getInputNamesAttr(), op.getOutputNamesAttr(),
385 rewriter.getArrayAttr({}),
nullptr,
389 op.replaceAllUsesWith(instOp.getResults());
390 rewriter.eraseOp(op);
395static void getValuesToObserve(Region *region,
396 function_ref<
void(Value)> setInsertionPoint,
397 const TypeConverter *typeConverter,
398 ConversionPatternRewriter &rewriter,
399 SmallVector<Value> &observeValues) {
400 SmallDenseSet<Value> alreadyObserved;
401 Location loc = region->getLoc();
403 auto probeIfSignal = [&](Value value) -> Value {
404 if (!isa<llhd::RefType>(value.getType()))
406 return llhd::ProbeOp::create(rewriter, loc, value);
409 region->getParentOp()->walk<WalkOrder::PreOrder, ForwardDominanceIterator<>>(
410 [&](Operation *operation) {
411 for (
auto value : operation->getOperands()) {
412 if (isa<BlockArgument>(value))
413 value = rewriter.getRemappedValue(value);
415 if (region->isAncestor(value.getParentRegion()))
417 if (
auto *defOp = value.getDefiningOp();
418 defOp && defOp->hasTrait<OpTrait::ConstantLike>())
420 if (!alreadyObserved.insert(value).second)
423 OpBuilder::InsertionGuard g(rewriter);
424 if (
auto remapped = rewriter.getRemappedValue(value)) {
425 setInsertionPoint(remapped);
426 observeValues.push_back(probeIfSignal(remapped));
428 setInsertionPoint(value);
429 auto type = typeConverter->convertType(value.getType());
430 auto converted = typeConverter->materializeTargetConversion(
431 rewriter, loc, type, value);
432 observeValues.push_back(probeIfSignal(converted));
439 using OpConversionPattern::OpConversionPattern;
442 matchAndRewrite(ProcedureOp op, OpAdaptor adaptor,
443 ConversionPatternRewriter &rewriter)
const override {
445 SmallVector<Value> observedValues;
446 if (op.getKind() == ProcedureKind::AlwaysComb ||
447 op.getKind() == ProcedureKind::AlwaysLatch) {
448 auto setInsertionPoint = [&](Value value) {
449 rewriter.setInsertionPoint(op);
451 getValuesToObserve(&op.getBody(), setInsertionPoint, typeConverter,
452 rewriter, observedValues);
455 auto loc = op.getLoc();
456 if (failed(rewriter.convertRegionTypes(&op.getBody(), *typeConverter)))
461 if (op.getKind() == ProcedureKind::Initial ||
462 op.getKind() == ProcedureKind::Final) {
464 if (op.getKind() == ProcedureKind::Initial)
465 newOp = llhd::ProcessOp::create(rewriter, loc, TypeRange{});
467 newOp = llhd::FinalOp::create(rewriter, loc);
468 auto &body = newOp->getRegion(0);
469 rewriter.inlineRegionBefore(op.getBody(), body, body.end());
471 llvm::make_early_inc_range(body.getOps<ReturnOp>())) {
472 rewriter.setInsertionPoint(returnOp);
473 rewriter.replaceOpWithNewOp<llhd::HaltOp>(returnOp, ValueRange{});
475 rewriter.eraseOp(op);
480 auto newOp = llhd::ProcessOp::create(rewriter, loc, TypeRange{});
485 rewriter.createBlock(&newOp.getBody());
486 auto *block = &op.getBody().front();
487 cf::BranchOp::create(rewriter, loc, block);
488 rewriter.inlineRegionBefore(op.getBody(), newOp.getBody(),
489 newOp.getBody().end());
497 if (op.getKind() == ProcedureKind::AlwaysComb ||
498 op.getKind() == ProcedureKind::AlwaysLatch) {
499 Block *waitBlock = rewriter.createBlock(&newOp.getBody());
500 llhd::WaitOp::create(rewriter, loc, ValueRange{}, Value(), observedValues,
501 ValueRange{}, block);
508 for (
auto returnOp :
llvm::make_early_inc_range(newOp.getOps<ReturnOp>())) {
509 rewriter.setInsertionPoint(returnOp);
510 cf::BranchOp::create(rewriter, loc, block);
511 rewriter.eraseOp(returnOp);
514 rewriter.eraseOp(op);
520 using OpConversionPattern::OpConversionPattern;
523 matchAndRewrite(WaitEventOp op, OpAdaptor adaptor,
524 ConversionPatternRewriter &rewriter)
const override {
558 rewriter.splitBlock(op->getBlock(), ++Block::iterator(op));
564 if (op.getBody().front().empty()) {
567 rewriter.replaceOpWithNewOp<llhd::HaltOp>(op, ValueRange{});
571 auto *waitBlock = rewriter.createBlock(resumeBlock);
572 auto *checkBlock = rewriter.createBlock(resumeBlock);
574 auto loc = op.getLoc();
575 rewriter.setInsertionPoint(op);
576 cf::BranchOp::create(rewriter, loc, waitBlock);
586 SmallVector<Value> valuesBefore;
587 rewriter.setInsertionPointToEnd(waitBlock);
588 auto clonedOp = cast<WaitEventOp>(rewriter.clone(*op));
589 bool allDetectsAreAnyChange =
true;
591 llvm::make_early_inc_range(clonedOp.getOps<DetectEventOp>())) {
592 if (detectOp.getEdge() != Edge::AnyChange || detectOp.getCondition())
593 allDetectsAreAnyChange =
false;
594 valuesBefore.push_back(detectOp.getInput());
595 rewriter.eraseOp(detectOp);
601 SmallVector<Value> observeValues;
602 auto setInsertionPointAfterDef = [&](Value value) {
603 if (
auto *op = value.getDefiningOp())
604 rewriter.setInsertionPointAfter(op);
605 if (
auto arg = dyn_cast<BlockArgument>(value))
606 rewriter.setInsertionPointToStart(value.getParentBlock());
609 getValuesToObserve(&clonedOp.getBody(), setInsertionPointAfterDef,
610 typeConverter, rewriter, observeValues);
615 auto waitOp = llhd::WaitOp::create(rewriter, loc, ValueRange{}, Value(),
616 observeValues, ValueRange{}, checkBlock);
617 rewriter.inlineBlockBefore(&clonedOp.getBody().front(), waitOp);
618 rewriter.eraseOp(clonedOp);
622 SmallVector<DetectEventOp> detectOps(op.getBody().getOps<DetectEventOp>());
623 rewriter.inlineBlockBefore(&op.getBody().front(), checkBlock,
625 rewriter.eraseOp(op);
629 auto computeTrigger = [&](Value before, Value after, Edge edge) -> Value {
630 assert(before.getType() == after.getType() &&
631 "mismatched types after clone op");
632 auto beforeType = cast<IntType>(before.getType());
636 if (beforeType.getWidth() != 1 && edge != Edge::AnyChange) {
637 constexpr int LSB = 0;
639 IntType::get(rewriter.getContext(), 1, beforeType.getDomain());
641 moore::ExtractOp::create(rewriter, loc, beforeType, before, LSB);
642 after = moore::ExtractOp::create(rewriter, loc, beforeType, after, LSB);
645 auto intType = rewriter.getIntegerType(beforeType.getWidth());
646 before = typeConverter->materializeTargetConversion(rewriter, loc,
648 after = typeConverter->materializeTargetConversion(rewriter, loc, intType,
651 if (edge == Edge::AnyChange)
652 return comb::ICmpOp::create(rewriter, loc, ICmpPredicate::ne, before,
655 SmallVector<Value> disjuncts;
658 if (edge == Edge::PosEdge || edge == Edge::BothEdges) {
660 comb::XorOp::create(rewriter, loc, before, trueVal,
true);
662 comb::AndOp::create(rewriter, loc, notOldVal, after,
true);
663 disjuncts.push_back(posedge);
666 if (edge == Edge::NegEdge || edge == Edge::BothEdges) {
668 comb::XorOp::create(rewriter, loc, after, trueVal,
true);
670 comb::AndOp::create(rewriter, loc, before, notCurrVal,
true);
671 disjuncts.push_back(posedge);
674 return rewriter.createOrFold<
comb::OrOp>(loc, disjuncts,
true);
681 SmallVector<Value> triggers;
682 for (
auto [detectOp, before] :
llvm::zip(detectOps, valuesBefore)) {
683 if (!allDetectsAreAnyChange) {
684 if (!isa<IntType>(before.getType()))
685 return detectOp->emitError() <<
"requires int operand";
687 rewriter.setInsertionPoint(detectOp);
689 computeTrigger(before, detectOp.getInput(), detectOp.getEdge());
690 if (detectOp.getCondition()) {
691 auto condition = typeConverter->materializeTargetConversion(
692 rewriter, loc, rewriter.getI1Type(), detectOp.getCondition());
694 comb::AndOp::create(rewriter, loc, trigger, condition,
true);
696 triggers.push_back(trigger);
699 rewriter.eraseOp(detectOp);
702 rewriter.setInsertionPointToEnd(checkBlock);
703 if (triggers.empty()) {
708 cf::BranchOp::create(rewriter, loc, resumeBlock);
714 auto triggered = rewriter.createOrFold<
comb::OrOp>(loc, triggers,
true);
715 cf::CondBranchOp::create(rewriter, loc, triggered, resumeBlock,
724static LogicalResult
convert(WaitDelayOp op, WaitDelayOp::Adaptor adaptor,
725 ConversionPatternRewriter &rewriter) {
727 rewriter.splitBlock(op->getBlock(), ++Block::iterator(op));
728 rewriter.setInsertionPoint(op);
729 rewriter.replaceOpWithNewOp<llhd::WaitOp>(op, ValueRange{},
730 adaptor.getDelay(), ValueRange{},
731 ValueRange{}, resumeBlock);
732 rewriter.setInsertionPointToStart(resumeBlock);
737static LogicalResult
convert(UnreachableOp op, UnreachableOp::Adaptor adaptor,
738 ConversionPatternRewriter &rewriter) {
739 rewriter.replaceOpWithNewOp<llhd::HaltOp>(op, ValueRange{});
748 ConversionPatternRewriter &rewriter) {
750 if (isa<mlir::LLVM::LLVMPointerType>(type))
751 return mlir::LLVM::ZeroOp::create(rewriter, loc, type);
754 if (isa<llhd::TimeType>(type)) {
756 llhd::TimeAttr::get(type.getContext(), 0U, llvm::StringRef(
"ns"), 0, 0);
757 return llhd::ConstantTimeOp::create(rewriter, loc, timeAttr);
761 if (
auto floatType = dyn_cast<FloatType>(type)) {
762 auto floatAttr = rewriter.getFloatAttr(floatType, 0.0);
763 return mlir::arith::ConstantOp::create(rewriter, loc, floatAttr);
767 if (
auto strType = dyn_cast<sim::DynamicStringType>(type))
768 return sim::StringConstantOp::create(rewriter, loc, strType,
"");
771 if (
auto queueType = dyn_cast<sim::QueueType>(type))
772 return sim::QueueEmptyOp::create(rewriter, loc, queueType);
775 int64_t width = hw::getBitWidth(type);
783 return rewriter.createOrFold<
hw::BitcastOp>(loc, type, constZero);
786struct ClassPropertyRefOpConversion
788 ClassPropertyRefOpConversion(TypeConverter &tc, MLIRContext *ctx,
789 ClassTypeCache &cache)
793 matchAndRewrite(circt::moore::ClassPropertyRefOp op, OpAdaptor adaptor,
794 ConversionPatternRewriter &rewriter)
const override {
795 Location loc = op.getLoc();
796 MLIRContext *ctx = rewriter.getContext();
799 Type dstTy = getTypeConverter()->convertType(op.getPropertyRef().getType());
801 Value instRef = adaptor.getInstance();
805 cast<circt::moore::ClassHandleType>(op.getInstance().getType());
806 SymbolRefAttr classSym = classRefTy.getClassSym();
807 ModuleOp mod = op->getParentOfType<ModuleOp>();
808 if (failed(resolveClassStructBody(mod, classSym, *typeConverter, cache)))
809 return rewriter.notifyMatchFailure(op,
810 "Could not resolve class struct for " +
811 classSym.getRootReference().str());
813 auto structInfo = cache.getStructInfo(classSym);
814 assert(structInfo &&
"class struct info must exist");
815 auto structTy = structInfo->classBody;
818 auto propSym = op.getProperty();
819 auto pathOpt = structInfo->getFieldPath(propSym);
821 return rewriter.notifyMatchFailure(op,
822 "no GEP path for property " + propSym);
824 auto i32Ty = IntegerType::get(ctx, 32);
825 SmallVector<Value> idxVals;
826 for (
unsigned idx : *pathOpt)
827 idxVals.push_back(LLVM::ConstantOp::create(
828 rewriter, loc, i32Ty, rewriter.getI32IntegerAttr(idx)));
831 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
833 LLVM::GEPOp::create(rewriter, loc, ptrTy, structTy, instRef, idxVals);
836 Value fieldRef = UnrealizedConversionCastOp::create(rewriter, loc, dstTy,
840 rewriter.replaceOp(op, fieldRef);
845 ClassTypeCache &cache;
849 using OpConversionPattern::OpConversionPattern;
852 matchAndRewrite(ClassUpcastOp op, OpAdaptor adaptor,
853 ConversionPatternRewriter &rewriter)
const override {
855 Type dstTy = getTypeConverter()->convertType(op.getResult().getType());
856 Type srcTy = adaptor.getInstance().getType();
859 return rewriter.notifyMatchFailure(op,
"failed to convert result type");
862 if (dstTy == srcTy && isa<LLVM::LLVMPointerType>(srcTy)) {
863 rewriter.replaceOp(op, adaptor.getInstance());
866 return rewriter.notifyMatchFailure(
867 op,
"Upcast applied to non-opaque pointers!");
873 ClassNewOpConversion(TypeConverter &tc, MLIRContext *ctx,
874 ClassTypeCache &cache)
878 matchAndRewrite(ClassNewOp op, OpAdaptor adaptor,
879 ConversionPatternRewriter &rewriter)
const override {
880 Location loc = op.getLoc();
881 MLIRContext *ctx = rewriter.getContext();
883 auto handleTy = cast<ClassHandleType>(op.getResult().getType());
884 auto sym = handleTy.getClassSym();
886 ModuleOp mod = op->getParentOfType<ModuleOp>();
888 if (failed(resolveClassStructBody(mod, sym, *typeConverter, cache)))
889 return op.emitError() <<
"Could not resolve class struct for " << sym;
891 auto structTy = cache.getStructInfo(sym)->classBody;
895 uint64_t byteSize = dl.getTypeSize(structTy);
896 auto i64Ty = IntegerType::get(ctx, 64);
897 auto cSize = LLVM::ConstantOp::create(rewriter, loc, i64Ty,
898 rewriter.getI64IntegerAttr(byteSize));
901 auto mallocFn = getOrCreateMalloc(mod, rewriter);
902 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
904 LLVM::CallOp::create(rewriter, loc, TypeRange{ptrTy},
905 SymbolRefAttr::get(mallocFn), ValueRange{cSize});
909 rewriter.replaceOp(op, call.getResult());
914 ClassTypeCache &cache;
918 ClassDeclOpConversion(TypeConverter &tc, MLIRContext *ctx,
919 ClassTypeCache &cache)
923 matchAndRewrite(ClassDeclOp op, OpAdaptor,
924 ConversionPatternRewriter &rewriter)
const override {
926 if (failed(resolveClassStructBody(op, *typeConverter, cache)))
929 rewriter.eraseOp(op);
934 ClassTypeCache &cache;
938 using OpConversionPattern::OpConversionPattern;
941 matchAndRewrite(VariableOp op, OpAdaptor adaptor,
942 ConversionPatternRewriter &rewriter)
const override {
943 auto loc = op.getLoc();
944 auto resultType = typeConverter->convertType(op.getResult().getType());
946 return rewriter.notifyMatchFailure(op.getLoc(),
"invalid variable type");
949 Value init = adaptor.getInitial();
951 auto elementType = cast<llhd::RefType>(resultType).getNestedType();
957 rewriter.replaceOpWithNewOp<llhd::SignalOp>(op, resultType,
958 op.getNameAttr(), init);
964 using OpConversionPattern::OpConversionPattern;
967 matchAndRewrite(NetOp op, OpAdaptor adaptor,
968 ConversionPatternRewriter &rewriter)
const override {
969 auto loc = op.getLoc();
971 auto resultType = typeConverter->convertType(op.getResult().getType());
973 return rewriter.notifyMatchFailure(loc,
"invalid net type");
975 auto elementType = cast<llhd::RefType>(resultType).getNestedType();
981 createInitialValue(op.getKind(), rewriter, loc, width,
elementType);
982 auto signal = rewriter.replaceOpWithNewOp<llhd::SignalOp>(
983 op, resultType, op.getNameAttr(), init);
985 if (
auto assignedValue = adaptor.getAssignment()) {
986 auto timeAttr = llhd::TimeAttr::get(resultType.getContext(), 0U,
987 llvm::StringRef(
"ns"), 0, 1);
988 auto time = llhd::ConstantTimeOp::create(rewriter, loc, timeAttr);
989 llhd::DriveOp::create(rewriter, loc, signal, assignedValue, time,
996 static mlir::Value createInitialValue(NetKind kind,
997 ConversionPatternRewriter &rewriter,
998 Location loc, int64_t width,
1009 if (kind == NetKind::Supply1 || kind == NetKind::Tri1)
1010 return APInt::getAllOnes(width);
1011 return APInt::getZero(width);
1019static LogicalResult
convert(GlobalVariableOp op,
1020 GlobalVariableOp::Adaptor adaptor,
1021 ConversionPatternRewriter &rewriter,
1022 const TypeConverter &typeConverter) {
1023 auto type = typeConverter.convertType(op.getType());
1024 auto sig = llhd::GlobalSignalOp::create(rewriter, op.getLoc(),
1025 op.getSymNameAttr(), type);
1026 sig.getInitRegion().takeBody(op.getInitRegion());
1027 rewriter.eraseOp(op);
1032static LogicalResult
convert(GetGlobalVariableOp op,
1033 GetGlobalVariableOp::Adaptor adaptor,
1034 ConversionPatternRewriter &rewriter,
1035 const TypeConverter &typeConverter) {
1036 auto type = typeConverter.convertType(op.getType());
1037 rewriter.replaceOpWithNewOp<llhd::GetGlobalSignalOp>(op, type,
1038 op.getGlobalNameAttr());
1047 using OpConversionPattern::OpConversionPattern;
1050 matchAndRewrite(ConstantOp op, OpAdaptor adaptor,
1051 ConversionPatternRewriter &rewriter)
const override {
1053 auto value = op.getValue().toAPInt(
false);
1054 auto type = rewriter.getIntegerType(value.getBitWidth());
1056 op, type, rewriter.getIntegerAttr(type, value));
1062 using OpConversionPattern::OpConversionPattern;
1065 matchAndRewrite(ConstantRealOp op, OpAdaptor adaptor,
1066 ConversionPatternRewriter &rewriter)
const override {
1067 rewriter.replaceOpWithNewOp<arith::ConstantOp>(op, op.getValueAttr());
1073 using OpConversionPattern::OpConversionPattern;
1076 matchAndRewrite(ConstantTimeOp op, OpAdaptor adaptor,
1077 ConversionPatternRewriter &rewriter)
const override {
1078 rewriter.replaceOpWithNewOp<llhd::ConstantTimeOp>(
1079 op, llhd::TimeAttr::get(op->getContext(), op.getValue(),
1080 StringRef(
"fs"), 0, 0));
1086 using OpConversionPattern::OpConversionPattern;
1088 matchAndRewrite(moore::ConstantStringOp op, OpAdaptor adaptor,
1089 ConversionPatternRewriter &rewriter)
const override {
1090 const auto resultType =
1091 typeConverter->convertType(op.getResult().getType());
1092 const auto intType = mlir::cast<IntegerType>(resultType);
1094 const auto str = op.getValue();
1095 const unsigned byteWidth = intType.getWidth();
1096 APInt value(byteWidth, 0);
1099 const size_t maxChars =
1100 std::min(str.size(),
static_cast<size_t>(byteWidth / 8));
1101 for (
size_t i = 0; i < maxChars; i++) {
1102 const size_t pos = str.size() - 1 - i;
1103 const auto asciiChar =
static_cast<uint8_t
>(str[pos]);
1104 value |= APInt(byteWidth, asciiChar) << (8 * i);
1108 op, resultType, rewriter.getIntegerAttr(resultType, value));
1114 using OpConversionPattern::OpConversionPattern;
1116 matchAndRewrite(ConcatOp op, OpAdaptor adaptor,
1117 ConversionPatternRewriter &rewriter)
const override {
1118 rewriter.replaceOpWithNewOp<
comb::ConcatOp>(op, adaptor.getValues());
1124 using OpConversionPattern::OpConversionPattern;
1126 matchAndRewrite(ReplicateOp op, OpAdaptor adaptor,
1127 ConversionPatternRewriter &rewriter)
const override {
1128 Type resultType = typeConverter->convertType(op.getResult().getType());
1130 rewriter.replaceOpWithNewOp<comb::ReplicateOp>(op, resultType,
1131 adaptor.getValue());
1137 using OpConversionPattern::OpConversionPattern;
1140 matchAndRewrite(ExtractOp op, OpAdaptor adaptor,
1141 ConversionPatternRewriter &rewriter)
const override {
1144 Type resultType = typeConverter->convertType(op.getResult().getType());
1145 Type inputType = adaptor.getInput().getType();
1146 int32_t low = adaptor.getLowBit();
1148 if (isa<IntegerType>(inputType)) {
1149 int32_t inputWidth = inputType.getIntOrFloatBitWidth();
1150 int32_t resultWidth = hw::getBitWidth(resultType);
1151 int32_t high = low + resultWidth;
1153 SmallVector<Value> toConcat;
1156 rewriter, op.getLoc(), APInt(std::min(-low, resultWidth), 0)));
1158 if (low < inputWidth && high > 0) {
1159 int32_t lowIdx = std::max(low, 0);
1162 rewriter.getIntegerType(
1163 std::min(resultWidth, std::min(high, inputWidth) - lowIdx)),
1164 adaptor.getInput(), lowIdx);
1165 toConcat.push_back(middle);
1168 int32_t diff = high - inputWidth;
1172 toConcat.push_back(val);
1177 rewriter.replaceOp(op, concat);
1181 if (
auto arrTy = dyn_cast<hw::ArrayType>(inputType)) {
1182 int32_t width = llvm::Log2_64_Ceil(arrTy.getNumElements());
1183 int32_t inputWidth = arrTy.getNumElements();
1185 if (
auto resArrTy = dyn_cast<hw::ArrayType>(resultType);
1186 resArrTy && resArrTy != arrTy.getElementType()) {
1187 int32_t elementWidth = hw::getBitWidth(arrTy.getElementType());
1188 if (elementWidth < 0)
1191 int32_t high = low + resArrTy.getNumElements();
1192 int32_t resWidth = resArrTy.getNumElements();
1194 SmallVector<Value> toConcat;
1197 rewriter, op.getLoc(),
1198 APInt(std::min((-low) * elementWidth, resWidth * elementWidth),
1201 op.getLoc(), hw::ArrayType::get(arrTy.getElementType(), -low),
1203 toConcat.push_back(res);
1206 if (low < inputWidth && high > 0) {
1207 int32_t lowIdx = std::max(0, low);
1209 rewriter, op.getLoc(), rewriter.getIntegerType(width), lowIdx);
1213 arrTy.getElementType(),
1214 std::min(resWidth, std::min(inputWidth, high) - lowIdx)),
1215 adaptor.getInput(), lowIdxVal);
1216 toConcat.push_back(middle);
1219 int32_t diff = high - inputWidth;
1222 rewriter, op.getLoc(), APInt(diff * elementWidth, 0));
1224 rewriter, op.getLoc(),
1225 hw::ArrayType::get(arrTy.getElementType(), diff), constZero);
1226 toConcat.push_back(val);
1231 rewriter.replaceOp(op, concat);
1236 if (low < 0 || low >= inputWidth) {
1237 int32_t bw = hw::getBitWidth(resultType);
1243 rewriter.createOrFold<
hw::BitcastOp>(op.getLoc(), resultType, val);
1244 rewriter.replaceOp(op, bitcast);
1249 rewriter.getIntegerType(width),
1250 adaptor.getLowBit());
1251 rewriter.replaceOpWithNewOp<
hw::ArrayGetOp>(op, adaptor.getInput(), idx);
1260 using OpConversionPattern::OpConversionPattern;
1263 matchAndRewrite(ExtractRefOp op, OpAdaptor adaptor,
1264 ConversionPatternRewriter &rewriter)
const override {
1266 Type resultType = typeConverter->convertType(op.getResult().getType());
1268 cast<llhd::RefType>(adaptor.getInput().getType()).getNestedType();
1270 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1271 int64_t width = hw::getBitWidth(inputType);
1276 rewriter, op.getLoc(),
1277 rewriter.getIntegerType(llvm::Log2_64_Ceil(width)),
1278 adaptor.getLowBit());
1279 rewriter.replaceOpWithNewOp<llhd::SigExtractOp>(
1280 op, resultType, adaptor.getInput(), lowBit);
1284 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1286 rewriter, op.getLoc(),
1287 rewriter.getIntegerType(llvm::Log2_64_Ceil(arrType.getNumElements())),
1288 adaptor.getLowBit());
1292 if (arrType.getElementType() !=
1293 cast<llhd::RefType>(resultType).getNestedType()) {
1294 rewriter.replaceOpWithNewOp<llhd::SigArraySliceOp>(
1295 op, resultType, adaptor.getInput(), lowBit);
1299 rewriter.replaceOpWithNewOp<llhd::SigArrayGetOp>(op, adaptor.getInput(),
1309 using OpConversionPattern::OpConversionPattern;
1312 matchAndRewrite(DynExtractOp op, OpAdaptor adaptor,
1313 ConversionPatternRewriter &rewriter)
const override {
1314 Type resultType = typeConverter->convertType(op.getResult().getType());
1315 Type inputType = adaptor.getInput().getType();
1317 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1318 Value amount = adjustIntegerWidth(rewriter, adaptor.getLowBit(),
1319 intType.getWidth(), op->getLoc());
1320 Value value = comb::ShrUOp::create(rewriter, op->getLoc(),
1321 adaptor.getInput(), amount);
1323 rewriter.replaceOpWithNewOp<
comb::ExtractOp>(op, resultType, value, 0);
1327 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1328 unsigned idxWidth = llvm::Log2_64_Ceil(arrType.getNumElements());
1329 Value idx = adjustIntegerWidth(rewriter, adaptor.getLowBit(), idxWidth,
1332 bool isSingleElementExtract = arrType.getElementType() == resultType;
1334 if (isSingleElementExtract)
1335 rewriter.replaceOpWithNewOp<
hw::ArrayGetOp>(op, adaptor.getInput(),
1339 adaptor.getInput(), idx);
1349 using OpConversionPattern::OpConversionPattern;
1352 matchAndRewrite(DynExtractRefOp op, OpAdaptor adaptor,
1353 ConversionPatternRewriter &rewriter)
const override {
1355 Type resultType = typeConverter->convertType(op.getResult().getType());
1357 cast<llhd::RefType>(adaptor.getInput().getType()).getNestedType();
1359 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1360 int64_t width = hw::getBitWidth(inputType);
1365 adjustIntegerWidth(rewriter, adaptor.getLowBit(),
1366 llvm::Log2_64_Ceil(width), op->getLoc());
1367 rewriter.replaceOpWithNewOp<llhd::SigExtractOp>(
1368 op, resultType, adaptor.getInput(), amount);
1372 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1373 Value idx = adjustIntegerWidth(
1374 rewriter, adaptor.getLowBit(),
1375 llvm::Log2_64_Ceil(arrType.getNumElements()), op->getLoc());
1377 auto resultNestedType = cast<llhd::RefType>(resultType).getNestedType();
1378 bool isSingleElementExtract =
1379 arrType.getElementType() == resultNestedType;
1381 if (isSingleElementExtract)
1382 rewriter.replaceOpWithNewOp<llhd::SigArrayGetOp>(op, adaptor.getInput(),
1385 rewriter.replaceOpWithNewOp<llhd::SigArraySliceOp>(
1386 op, resultType, adaptor.getInput(), idx);
1396 using OpConversionPattern::OpConversionPattern;
1399 matchAndRewrite(ArrayCreateOp op, OpAdaptor adaptor,
1400 ConversionPatternRewriter &rewriter)
const override {
1401 Type resultType = typeConverter->convertType(op.getResult().getType());
1403 adaptor.getElements());
1409 using OpConversionPattern::OpConversionPattern;
1412 matchAndRewrite(StructCreateOp op, OpAdaptor adaptor,
1413 ConversionPatternRewriter &rewriter)
const override {
1414 Type resultType = typeConverter->convertType(op.getResult().getType());
1416 adaptor.getFields());
1422 using OpConversionPattern::OpConversionPattern;
1425 matchAndRewrite(StructExtractOp op, OpAdaptor adaptor,
1426 ConversionPatternRewriter &rewriter)
const override {
1428 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1433struct StructExtractRefOpConversion
1435 using OpConversionPattern::OpConversionPattern;
1438 matchAndRewrite(StructExtractRefOp op, OpAdaptor adaptor,
1439 ConversionPatternRewriter &rewriter)
const override {
1440 rewriter.replaceOpWithNewOp<llhd::SigStructExtractOp>(
1441 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1447 using OpConversionPattern::OpConversionPattern;
1450 matchAndRewrite(UnionCreateOp op, OpAdaptor adaptor,
1451 ConversionPatternRewriter &rewriter)
const override {
1452 Type resultType = typeConverter->convertType(op.getResult().getType());
1453 rewriter.replaceOpWithNewOp<hw::UnionCreateOp>(
1454 op, resultType, adaptor.getFieldNameAttr(), adaptor.getInput());
1460 using OpConversionPattern::OpConversionPattern;
1463 matchAndRewrite(UnionExtractOp op, OpAdaptor adaptor,
1464 ConversionPatternRewriter &rewriter)
const override {
1465 rewriter.replaceOpWithNewOp<hw::UnionExtractOp>(op, adaptor.getInput(),
1466 adaptor.getFieldNameAttr());
1471struct UnionExtractRefOpConversion
1473 using OpConversionPattern::OpConversionPattern;
1476 matchAndRewrite(UnionExtractRefOp op, OpAdaptor adaptor,
1477 ConversionPatternRewriter &rewriter)
const override {
1478 rewriter.replaceOpWithNewOp<llhd::SigStructExtractOp>(
1479 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1485 using OpConversionPattern::OpConversionPattern;
1487 matchAndRewrite(ReduceAndOp op, OpAdaptor adaptor,
1488 ConversionPatternRewriter &rewriter)
const override {
1489 Type resultType = typeConverter->convertType(op.getInput().getType());
1492 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::eq,
1493 adaptor.getInput(), max);
1499 using OpConversionPattern::OpConversionPattern;
1501 matchAndRewrite(ReduceOrOp op, OpAdaptor adaptor,
1502 ConversionPatternRewriter &rewriter)
const override {
1503 Type resultType = typeConverter->convertType(op.getInput().getType());
1506 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1507 adaptor.getInput(), zero);
1513 using OpConversionPattern::OpConversionPattern;
1515 matchAndRewrite(ReduceXorOp op, OpAdaptor adaptor,
1516 ConversionPatternRewriter &rewriter)
const override {
1518 rewriter.replaceOpWithNewOp<
comb::ParityOp>(op, adaptor.getInput());
1524 using OpConversionPattern::OpConversionPattern;
1526 matchAndRewrite(BoolCastOp op, OpAdaptor adaptor,
1527 ConversionPatternRewriter &rewriter)
const override {
1528 Type resultType = typeConverter->convertType(op.getInput().getType());
1529 if (isa_and_nonnull<IntegerType>(resultType)) {
1532 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1533 adaptor.getInput(), zero);
1541 using OpConversionPattern::OpConversionPattern;
1543 matchAndRewrite(NotOp op, OpAdaptor adaptor,
1544 ConversionPatternRewriter &rewriter)
const override {
1546 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1549 rewriter.replaceOpWithNewOp<
comb::XorOp>(op, adaptor.getInput(), max);
1555 using OpConversionPattern::OpConversionPattern;
1557 matchAndRewrite(NegOp op, OpAdaptor adaptor,
1558 ConversionPatternRewriter &rewriter)
const override {
1560 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1563 rewriter.replaceOpWithNewOp<
comb::SubOp>(op, zero, adaptor.getInput());
1569 using OpConversionPattern::OpConversionPattern;
1571 matchAndRewrite(NegRealOp op, OpAdaptor adaptor,
1572 ConversionPatternRewriter &rewriter)
const override {
1573 rewriter.replaceOpWithNewOp<arith::NegFOp>(op, adaptor.getInput());
1578template <
typename SourceOp,
typename TargetOp>
1581 using OpAdaptor =
typename SourceOp::Adaptor;
1584 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1585 ConversionPatternRewriter &rewriter)
const override {
1586 rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(),
1587 adaptor.getRhs(),
false);
1592template <
typename SourceOp,
typename TargetOp>
1595 using OpAdaptor =
typename SourceOp::Adaptor;
1598 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1599 ConversionPatternRewriter &rewriter)
const override {
1600 rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(),
1606template <
typename SourceOp, ICmpPredicate pred>
1609 using OpAdaptor =
typename SourceOp::Adaptor;
1612 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1613 ConversionPatternRewriter &rewriter)
const override {
1615 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1617 rewriter.replaceOpWithNewOp<comb::ICmpOp>(
1618 op, resultType, pred, adaptor.getLhs(), adaptor.getRhs());
1623template <
typename SourceOp, arith::CmpFPredicate pred>
1626 using OpAdaptor =
typename SourceOp::Adaptor;
1629 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1630 ConversionPatternRewriter &rewriter)
const override {
1632 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1634 rewriter.replaceOpWithNewOp<arith::CmpFOp>(
1635 op, resultType, pred, adaptor.getLhs(), adaptor.getRhs());
1640template <
typename SourceOp,
bool withoutX>
1643 using OpAdaptor =
typename SourceOp::Adaptor;
1646 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1647 ConversionPatternRewriter &rewriter)
const override {
1653 unsigned bitWidth = op.getLhs().getType().getWidth();
1654 auto ignoredBits = APInt::getZero(bitWidth);
1655 auto detectIgnoredBits = [&](Value value) {
1656 auto constOp = value.getDefiningOp<ConstantOp>();
1659 auto constValue = constOp.getValue();
1661 ignoredBits |= constValue.getZBits();
1663 ignoredBits |= constValue.getUnknownBits();
1665 detectIgnoredBits(op.getLhs());
1666 detectIgnoredBits(op.getRhs());
1670 Value lhs = adaptor.getLhs();
1671 Value rhs = adaptor.getRhs();
1672 if (!ignoredBits.isZero()) {
1673 ignoredBits.flipAllBits();
1675 lhs = rewriter.createOrFold<
comb::AndOp>(op.getLoc(), lhs, maskOp);
1676 rhs = rewriter.createOrFold<
comb::AndOp>(op.getLoc(), rhs, maskOp);
1679 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, ICmpPredicate::ceq, lhs, rhs);
1689 using OpConversionPattern::OpConversionPattern;
1692 matchAndRewrite(ConversionOp op, OpAdaptor adaptor,
1693 ConversionPatternRewriter &rewriter)
const override {
1694 Location loc = op.getLoc();
1695 Type resultType = typeConverter->convertType(op.getResult().getType());
1697 op.emitError(
"conversion result type is not currently supported");
1700 int64_t inputBw = hw::getBitWidth(adaptor.getInput().getType());
1701 int64_t resultBw = hw::getBitWidth(resultType);
1702 if (inputBw == -1 || resultBw == -1) {
1703 if (isSupportedDpiOpenArrayCast(op.getInput().getType(),
1704 op.getResult().getType())) {
1705 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
1706 op, resultType, adaptor.getInput());
1709 if (hasOpenArrayBoundaryType(op.getInput().getType()) ||
1710 hasOpenArrayBoundaryType(op.getResult().getType())) {
1711 op.emitError(
"unsupported DPI open-array conversion from ")
1712 << op.getInput().getType() <<
" to " << op.getResult().getType();
1719 loc, rewriter.getIntegerType(inputBw), adaptor.getInput());
1720 Value amount = adjustIntegerWidth(rewriter, input, resultBw, loc);
1723 rewriter.createOrFold<
hw::BitcastOp>(loc, resultType, amount);
1724 rewriter.replaceOp(op, result);
1729template <
typename SourceOp>
1732 using OpAdaptor =
typename SourceOp::Adaptor;
1733 using ConversionPattern::typeConverter;
1736 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1737 ConversionPatternRewriter &rewriter)
const override {
1738 auto type = typeConverter->convertType(op.getResult().getType());
1739 if (type == adaptor.getInput().getType())
1740 rewriter.replaceOp(op, adaptor.getInput());
1742 rewriter.replaceOpWithNewOp<
hw::BitcastOp>(op, type, adaptor.getInput());
1748template <
typename SourceOp>
1751 using OpAdaptor =
typename SourceOp::Adaptor;
1752 using ConversionPattern::typeConverter;
1755 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1756 ConversionPatternRewriter &rewriter)
const override {
1757 rewriter.replaceOp(op, adaptor.getInput());
1763 using OpConversionPattern::OpConversionPattern;
1766 matchAndRewrite(TruncOp op, OpAdaptor adaptor,
1767 ConversionPatternRewriter &rewriter)
const override {
1768 rewriter.replaceOpWithNewOp<
comb::ExtractOp>(op, adaptor.getInput(), 0,
1769 op.getType().getWidth());
1775 using OpConversionPattern::OpConversionPattern;
1778 matchAndRewrite(ZExtOp op, OpAdaptor adaptor,
1779 ConversionPatternRewriter &rewriter)
const override {
1780 auto targetWidth = op.getType().getWidth();
1781 auto inputWidth = op.getInput().getType().getWidth();
1784 rewriter, op.getLoc(),
1785 rewriter.getIntegerType(targetWidth - inputWidth), 0);
1788 op, ValueRange{zeroExt, adaptor.getInput()});
1794 using OpConversionPattern::OpConversionPattern;
1797 matchAndRewrite(SExtOp op, OpAdaptor adaptor,
1798 ConversionPatternRewriter &rewriter)
const override {
1799 auto type = typeConverter->convertType(op.getType());
1801 comb::createOrFoldSExt(rewriter, op.getLoc(), adaptor.getInput(), type);
1802 rewriter.replaceOp(op, value);
1808 using OpConversionPattern::OpConversionPattern;
1811 matchAndRewrite(SIntToRealOp op, OpAdaptor adaptor,
1812 ConversionPatternRewriter &rewriter)
const override {
1813 rewriter.replaceOpWithNewOp<arith::SIToFPOp>(
1814 op, typeConverter->convertType(op.getType()), adaptor.getInput());
1820 using OpConversionPattern::OpConversionPattern;
1823 matchAndRewrite(UIntToRealOp op, OpAdaptor adaptor,
1824 ConversionPatternRewriter &rewriter)
const override {
1825 rewriter.replaceOpWithNewOp<arith::UIToFPOp>(
1826 op, typeConverter->convertType(op.getType()), adaptor.getInput());
1832 using OpConversionPattern::OpConversionPattern;
1835 matchAndRewrite(IntToStringOp op, OpAdaptor adaptor,
1836 ConversionPatternRewriter &rewriter)
const override {
1837 rewriter.replaceOpWithNewOp<sim::IntToStringOp>(op, adaptor.getInput());
1843 using OpConversionPattern::OpConversionPattern;
1846 matchAndRewrite(RealToIntOp op, OpAdaptor adaptor,
1847 ConversionPatternRewriter &rewriter)
const override {
1848 rewriter.replaceOpWithNewOp<arith::FPToSIOp>(
1849 op, typeConverter->convertType(op.getType()), adaptor.getInput());
1859 using OpConversionPattern::OpConversionPattern;
1862 matchAndRewrite(hw::InstanceOp op, OpAdaptor adaptor,
1863 ConversionPatternRewriter &rewriter)
const override {
1864 SmallVector<Type> convResTypes;
1865 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
1868 rewriter.replaceOpWithNewOp<hw::InstanceOp>(
1869 op, convResTypes, op.getInstanceName(), op.getModuleName(),
1870 adaptor.getOperands(), op.getArgNames(),
1871 op.getResultNames(),
1872 rewriter.getArrayAttr({}),
nullptr);
1879 using OpConversionPattern::OpConversionPattern;
1882 matchAndRewrite(func::ReturnOp op, OpAdaptor adaptor,
1883 ConversionPatternRewriter &rewriter)
const override {
1884 rewriter.replaceOpWithNewOp<func::ReturnOp>(op, adaptor.getOperands());
1890 using OpConversionPattern::OpConversionPattern;
1893 matchAndRewrite(func::CallOp op, OpAdaptor adaptor,
1894 ConversionPatternRewriter &rewriter)
const override {
1895 SmallVector<Type> convResTypes;
1896 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
1898 rewriter.replaceOpWithNewOp<func::CallOp>(
1899 op, adaptor.getCallee(), convResTypes, adaptor.getOperands());
1904struct UnrealizedConversionCastConversion
1906 using OpConversionPattern::OpConversionPattern;
1909 matchAndRewrite(UnrealizedConversionCastOp op, OpAdaptor adaptor,
1910 ConversionPatternRewriter &rewriter)
const override {
1911 SmallVector<Type> convResTypes;
1912 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
1917 if (convResTypes == adaptor.getOperands().getTypes()) {
1918 rewriter.replaceOp(op, adaptor.getOperands());
1922 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
1923 op, convResTypes, adaptor.getOperands());
1929 using OpConversionPattern::OpConversionPattern;
1932 matchAndRewrite(ShlOp op, OpAdaptor adaptor,
1933 ConversionPatternRewriter &rewriter)
const override {
1934 Type resultType = typeConverter->convertType(op.getResult().getType());
1938 adjustIntegerWidth(rewriter, adaptor.getAmount(),
1939 resultType.getIntOrFloatBitWidth(), op->getLoc());
1940 rewriter.replaceOpWithNewOp<
comb::ShlOp>(op, resultType, adaptor.getValue(),
1947 using OpConversionPattern::OpConversionPattern;
1950 matchAndRewrite(ShrOp op, OpAdaptor adaptor,
1951 ConversionPatternRewriter &rewriter)
const override {
1952 Type resultType = typeConverter->convertType(op.getResult().getType());
1956 adjustIntegerWidth(rewriter, adaptor.getAmount(),
1957 resultType.getIntOrFloatBitWidth(), op->getLoc());
1959 op, resultType, adaptor.getValue(), amount,
false);
1965 using OpConversionPattern::OpConversionPattern;
1968 matchAndRewrite(PowUOp op, OpAdaptor adaptor,
1969 ConversionPatternRewriter &rewriter)
const override {
1970 Type resultType = typeConverter->convertType(op.getResult().getType());
1972 Location loc = op->getLoc();
1977 auto lhs = comb::ConcatOp::create(rewriter, loc, zeroVal, adaptor.getLhs());
1978 auto rhs = comb::ConcatOp::create(rewriter, loc, zeroVal, adaptor.getRhs());
1981 auto pow = mlir::math::IPowIOp::create(rewriter, loc, lhs, rhs);
1989 using OpConversionPattern::OpConversionPattern;
1992 matchAndRewrite(PowSOp op, OpAdaptor adaptor,
1993 ConversionPatternRewriter &rewriter)
const override {
1994 Type resultType = typeConverter->convertType(op.getResult().getType());
1998 rewriter.replaceOpWithNewOp<mlir::math::IPowIOp>(
1999 op, resultType, adaptor.getLhs(), adaptor.getRhs());
2005 using OpConversionPattern::OpConversionPattern;
2008 matchAndRewrite(AShrOp op, OpAdaptor adaptor,
2009 ConversionPatternRewriter &rewriter)
const override {
2010 Type resultType = typeConverter->convertType(op.getResult().getType());
2014 adjustIntegerWidth(rewriter, adaptor.getAmount(),
2015 resultType.getIntOrFloatBitWidth(), op->getLoc());
2017 op, resultType, adaptor.getValue(), amount,
false);
2023 using OpConversionPattern::OpConversionPattern;
2026 matchAndRewrite(ReadOp op, OpAdaptor adaptor,
2027 ConversionPatternRewriter &rewriter)
const override {
2028 rewriter.replaceOpWithNewOp<llhd::ProbeOp>(op, adaptor.getInput());
2033struct AssignedVariableOpConversion
2035 using OpConversionPattern::OpConversionPattern;
2038 matchAndRewrite(AssignedVariableOp op, OpAdaptor adaptor,
2039 ConversionPatternRewriter &rewriter)
const override {
2040 rewriter.replaceOpWithNewOp<hw::WireOp>(op, adaptor.getInput(),
2041 adaptor.getNameAttr());
2047static llhd::TimeAttr
2048getBlockingOrContinuousAssignDelay(mlir::MLIRContext *
context) {
2049 return llhd::TimeAttr::get(
context, 0U,
"ns", 0, 1);
2052template <
typename OpTy>
2055 using OpAdaptor =
typename OpTy::Adaptor;
2058 matchAndRewrite(OpTy op, OpAdaptor adaptor,
2059 ConversionPatternRewriter &rewriter)
const override {
2062 if constexpr (std::is_same_v<OpTy, ContinuousAssignOp> ||
2063 std::is_same_v<OpTy, BlockingAssignOp>) {
2064 delay = llhd::ConstantTimeOp::create(
2065 rewriter, op->getLoc(),
2066 getBlockingOrContinuousAssignDelay(op->getContext()));
2067 }
else if constexpr (std::is_same_v<OpTy, NonBlockingAssignOp>) {
2069 delay = llhd::ConstantTimeOp::create(
2070 rewriter, op->getLoc(),
2071 llhd::TimeAttr::get(op->getContext(), 0U,
"ns", 1, 0));
2074 delay = adaptor.getDelay();
2077 rewriter.replaceOpWithNewOp<llhd::DriveOp>(
2078 op, adaptor.getDst(), adaptor.getSrc(), delay, Value{});
2084 using OpConversionPattern::OpConversionPattern;
2087 matchAndRewrite(ConditionalOp op, OpAdaptor adaptor,
2088 ConversionPatternRewriter &rewriter)
const override {
2093 auto type = typeConverter->convertType(op.getType());
2095 auto hasNoWriteEffect = [](Region ®ion) {
2096 auto result = region.walk([](Operation *operation) {
2097 if (
auto memOp = dyn_cast<MemoryEffectOpInterface>(operation))
2098 if (!memOp.hasEffect<MemoryEffects::Write>() &&
2099 !memOp.hasEffect<MemoryEffects::Free>())
2100 return WalkResult::advance();
2102 if (operation->hasTrait<OpTrait::HasRecursiveMemoryEffects>())
2103 return WalkResult::advance();
2105 return WalkResult::interrupt();
2107 return !result.wasInterrupted();
2110 if (hasNoWriteEffect(op.getTrueRegion()) &&
2111 hasNoWriteEffect(op.getFalseRegion())) {
2112 Operation *trueTerm = op.getTrueRegion().front().getTerminator();
2113 Operation *falseTerm = op.getFalseRegion().front().getTerminator();
2115 rewriter.inlineBlockBefore(&op.getTrueRegion().front(), op);
2116 rewriter.inlineBlockBefore(&op.getFalseRegion().front(), op);
2118 Value convTrueVal = typeConverter->materializeTargetConversion(
2119 rewriter, op.getLoc(), type, trueTerm->getOperand(0));
2120 Value convFalseVal = typeConverter->materializeTargetConversion(
2121 rewriter, op.getLoc(), type, falseTerm->getOperand(0));
2123 rewriter.eraseOp(trueTerm);
2124 rewriter.eraseOp(falseTerm);
2126 rewriter.replaceOpWithNewOp<
comb::MuxOp>(op, adaptor.getCondition(),
2127 convTrueVal, convFalseVal);
2132 scf::IfOp::create(rewriter, op.getLoc(), type, adaptor.getCondition());
2133 rewriter.inlineRegionBefore(op.getTrueRegion(), ifOp.getThenRegion(),
2134 ifOp.getThenRegion().end());
2135 rewriter.inlineRegionBefore(op.getFalseRegion(), ifOp.getElseRegion(),
2136 ifOp.getElseRegion().end());
2137 rewriter.replaceOp(op, ifOp);
2143 using OpConversionPattern::OpConversionPattern;
2146 matchAndRewrite(YieldOp op, OpAdaptor adaptor,
2147 ConversionPatternRewriter &rewriter)
const override {
2148 if (isa<llhd::GlobalSignalOp>(op->getParentOp()))
2149 rewriter.replaceOpWithNewOp<llhd::YieldOp>(op, adaptor.getResult());
2151 rewriter.replaceOpWithNewOp<scf::YieldOp>(op, adaptor.getResult());
2156template <
typename SourceOp>
2159 using OpAdaptor =
typename SourceOp::Adaptor;
2162 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
2163 ConversionPatternRewriter &rewriter)
const override {
2164 rewriter.modifyOpInPlace(op,
2165 [&]() { op->setOperands(adaptor.getOperands()); });
2170template <
typename MooreOpTy,
typename VerifOpTy>
2173 using OpAdaptor =
typename MooreOpTy::Adaptor;
2176 matchAndRewrite(MooreOpTy op, OpAdaptor adaptor,
2177 ConversionPatternRewriter &rewriter)
const override {
2179 op.getLabel().has_value()
2180 ? StringAttr::get(op->getContext(), op.getLabel().value())
2181 : StringAttr::
get(op->getContext());
2182 rewriter.replaceOpWithNewOp<VerifOpTy>(op, adaptor.getCond(), mlir::Value(),
2193 using OpConversionPattern::OpConversionPattern;
2196 matchAndRewrite(FormatLiteralOp op, OpAdaptor adaptor,
2197 ConversionPatternRewriter &rewriter)
const override {
2198 rewriter.replaceOpWithNewOp<sim::FormatLiteralOp>(op, adaptor.getLiteral());
2204 using OpConversionPattern::OpConversionPattern;
2207 matchAndRewrite(FormatConcatOp op, OpAdaptor adaptor,
2208 ConversionPatternRewriter &rewriter)
const override {
2209 rewriter.replaceOpWithNewOp<sim::FormatStringConcatOp>(op,
2210 adaptor.getInputs());
2215struct FormatHierPathOpConversion
2217 using OpConversionPattern::OpConversionPattern;
2220 matchAndRewrite(FormatHierPathOp op, OpAdaptor adaptor,
2221 ConversionPatternRewriter &rewriter)
const override {
2222 rewriter.replaceOpWithNewOp<sim::FormatHierPathOp>(op,
2223 adaptor.getUseEscapes());
2229 using OpConversionPattern::OpConversionPattern;
2232 matchAndRewrite(FormatIntOp op, OpAdaptor adaptor,
2233 ConversionPatternRewriter &rewriter)
const override {
2235 char padChar = adaptor.getPadding() == IntPadding::Space ? 32 : 48;
2236 IntegerAttr padCharAttr = rewriter.getI8IntegerAttr(padChar);
2237 auto widthAttr = adaptor.getSpecifierWidthAttr();
2239 bool isLeftAligned = adaptor.getAlignment() == IntAlign::Left;
2240 BoolAttr isLeftAlignedAttr = rewriter.getBoolAttr(isLeftAligned);
2242 switch (op.getFormat()) {
2243 case IntFormat::Decimal:
2244 rewriter.replaceOpWithNewOp<sim::FormatDecOp>(
2245 op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr,
2246 adaptor.getIsSignedAttr());
2248 case IntFormat::Binary:
2249 rewriter.replaceOpWithNewOp<sim::FormatBinOp>(
2250 op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr);
2252 case IntFormat::Octal:
2253 rewriter.replaceOpWithNewOp<sim::FormatOctOp>(
2254 op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr);
2256 case IntFormat::HexLower:
2257 rewriter.replaceOpWithNewOp<sim::FormatHexOp>(
2258 op, adaptor.getValue(), rewriter.getBoolAttr(
false),
2259 isLeftAlignedAttr, padCharAttr, widthAttr);
2261 case IntFormat::HexUpper:
2262 rewriter.replaceOpWithNewOp<sim::FormatHexOp>(
2263 op, adaptor.getValue(), rewriter.getBoolAttr(
true), isLeftAlignedAttr,
2264 padCharAttr, widthAttr);
2267 return rewriter.notifyMatchFailure(op,
"unsupported int format");
2272 using OpConversionPattern::OpConversionPattern;
2275 matchAndRewrite(FormatRealOp op, OpAdaptor adaptor,
2276 ConversionPatternRewriter &rewriter)
const override {
2277 auto fracDigitsAttr = adaptor.getFracDigitsAttr();
2279 auto fieldWidthAttr = adaptor.getFieldWidthAttr();
2280 bool isLeftAligned = adaptor.getAlignment() == IntAlign::Left;
2281 mlir::BoolAttr isLeftAlignedAttr = rewriter.getBoolAttr(isLeftAligned);
2283 switch (op.getFormat()) {
2284 case RealFormat::General:
2285 rewriter.replaceOpWithNewOp<sim::FormatGeneralOp>(
2286 op, adaptor.getValue(), isLeftAlignedAttr, fieldWidthAttr,
2289 case RealFormat::Float:
2290 rewriter.replaceOpWithNewOp<sim::FormatFloatOp>(
2291 op, adaptor.getValue(), isLeftAlignedAttr, fieldWidthAttr,
2294 case RealFormat::Exponential:
2295 rewriter.replaceOpWithNewOp<sim::FormatScientificOp>(
2296 op, adaptor.getValue(), isLeftAlignedAttr, fieldWidthAttr,
2304 using OpConversionPattern::OpConversionPattern;
2307 matchAndRewrite(StringLenOp op, OpAdaptor adaptor,
2308 ConversionPatternRewriter &rewriter)
const override {
2309 rewriter.replaceOpWithNewOp<sim::StringLengthOp>(op, adaptor.getStr());
2315 using OpConversionPattern::OpConversionPattern;
2318 matchAndRewrite(StringConcatOp op, OpAdaptor adaptor,
2319 ConversionPatternRewriter &rewriter)
const override {
2320 rewriter.replaceOpWithNewOp<sim::StringConcatOp>(op, adaptor.getInputs());
2326 using OpConversionPattern::OpConversionPattern;
2329 matchAndRewrite(StringGetOp op, OpAdaptor adaptor,
2330 ConversionPatternRewriter &rewriter)
const override {
2331 rewriter.replaceOpWithNewOp<sim::StringGetOp>(op, adaptor.getStr(),
2332 adaptor.getIndex());
2338 using OpConversionPattern::OpConversionPattern;
2341 matchAndRewrite(QueueSizeBIOp op, OpAdaptor adaptor,
2342 ConversionPatternRewriter &rewriter)
const override {
2343 rewriter.replaceOpWithNewOp<sim::QueueSizeOp>(op, adaptor.getQueue());
2348struct DynQueueExtractOpConversion
2350 using OpConversionPattern::OpConversionPattern;
2353 matchAndRewrite(DynQueueExtractOp op, OpAdaptor adaptor,
2354 ConversionPatternRewriter &rewriter)
const override {
2355 bool isSingleElementExtract =
2356 op.getInput().getType().getElementType() == op.getResult().getType();
2358 if (isSingleElementExtract) {
2359 rewriter.replaceOpWithNewOp<sim::QueueGetOp>(op, adaptor.getInput(),
2360 adaptor.getLowerIdx());
2362 rewriter.replaceOpWithNewOp<sim::QueueSliceOp>(
2363 op, adaptor.getInput(), adaptor.getLowerIdx(), adaptor.getUpperIdx());
2379probeRefAndDriveWithResult(OpBuilder &builder, Location loc, Value ref,
2380 const std::function<Value(Value)> &func) {
2382 Value v = llhd::ProbeOp::create(builder, loc, ref);
2385 Value delay = llhd::ConstantTimeOp::create(
2386 builder, loc, getBlockingOrContinuousAssignDelay(builder.getContext()));
2388 llhd::DriveOp::create(builder, loc, ref, func(v), delay, Value{});
2392 using OpConversionPattern::OpConversionPattern;
2395 matchAndRewrite(QueuePushBackOp op, OpAdaptor adaptor,
2396 ConversionPatternRewriter &rewriter)
const override {
2397 probeRefAndDriveWithResult(
2398 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2399 return sim::QueuePushBackOp::create(rewriter, op->getLoc(), queue,
2400 adaptor.getElement());
2403 rewriter.eraseOp(op);
2408struct QueuePushFrontOpConversion
2410 using OpConversionPattern::OpConversionPattern;
2413 matchAndRewrite(QueuePushFrontOp op, OpAdaptor adaptor,
2414 ConversionPatternRewriter &rewriter)
const override {
2416 probeRefAndDriveWithResult(
2417 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2418 return sim::QueuePushFrontOp::create(rewriter, op->getLoc(), queue,
2419 adaptor.getElement());
2422 rewriter.eraseOp(op);
2428 using OpConversionPattern::OpConversionPattern;
2431 matchAndRewrite(QueuePopBackOp op, OpAdaptor adaptor,
2432 ConversionPatternRewriter &rewriter)
const override {
2433 probeRefAndDriveWithResult(
2434 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2436 sim::QueuePopBackOp::create(rewriter, op->getLoc(), queue);
2438 op.replaceAllUsesWith(popBack.getPopped());
2439 return popBack.getOutQueue();
2441 rewriter.eraseOp(op);
2448 using OpConversionPattern::OpConversionPattern;
2451 matchAndRewrite(QueuePopFrontOp op, OpAdaptor adaptor,
2452 ConversionPatternRewriter &rewriter)
const override {
2453 probeRefAndDriveWithResult(
2454 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2456 sim::QueuePopFrontOp::create(rewriter, op->getLoc(), queue);
2458 op.replaceAllUsesWith(popFront.getPopped());
2459 return popFront.getOutQueue();
2461 rewriter.eraseOp(op);
2468 using OpConversionPattern::OpConversionPattern;
2471 matchAndRewrite(QueueClearOp op, OpAdaptor adaptor,
2472 ConversionPatternRewriter &rewriter)
const override {
2473 auto refType = cast<llhd::RefType>(adaptor.getQueue().getType());
2474 auto queueType = refType.getNestedType();
2476 sim::QueueEmptyOp::create(rewriter, op->getLoc(), queueType);
2479 Value delay = llhd::ConstantTimeOp::create(
2480 rewriter, op.getLoc(),
2481 getBlockingOrContinuousAssignDelay(rewriter.getContext()));
2483 llhd::DriveOp::create(rewriter, op.getLoc(), adaptor.getQueue(), emptyQueue,
2486 rewriter.eraseOp(op);
2492 using OpConversionPattern::OpConversionPattern;
2495 matchAndRewrite(QueueInsertOp op, OpAdaptor adaptor,
2496 ConversionPatternRewriter &rewriter)
const override {
2497 probeRefAndDriveWithResult(
2498 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2500 sim::QueueInsertOp::create(rewriter, op->getLoc(), queue,
2501 adaptor.getIndex(), adaptor.getItem());
2503 return insert.getOutQueue();
2505 rewriter.eraseOp(op);
2512 using OpConversionPattern::OpConversionPattern;
2515 matchAndRewrite(QueueDeleteOp op, OpAdaptor adaptor,
2516 ConversionPatternRewriter &rewriter)
const override {
2517 probeRefAndDriveWithResult(
2518 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2519 auto delOp = sim::QueueDeleteOp::create(rewriter, op->getLoc(), queue,
2520 adaptor.getIndex());
2522 return delOp.getOutQueue();
2524 rewriter.eraseOp(op);
2531 using OpConversionPattern::OpConversionPattern;
2534 matchAndRewrite(QueueResizeOp op, OpAdaptor adaptor,
2535 ConversionPatternRewriter &rewriter)
const override {
2537 rewriter.replaceOpWithNewOp<sim::QueueResizeOp>(
2538 op, getTypeConverter()->convertType(op.getResult().getType()),
2539 adaptor.getInput());
2545 using OpConversionPattern::OpConversionPattern;
2547 matchAndRewrite(QueueSetOp op, OpAdaptor adaptor,
2548 ConversionPatternRewriter &rewriter)
const override {
2549 probeRefAndDriveWithResult(
2550 rewriter, op->getLoc(), adaptor.getQueue(), [&](Value queue) {
2552 sim::QueueSetOp::create(rewriter, op.getLoc(), queue,
2553 adaptor.getIndex(), adaptor.getItem());
2554 return setOp.getOutQueue();
2556 rewriter.eraseOp(op);
2562 using OpConversionPattern::OpConversionPattern;
2565 matchAndRewrite(QueueCmpOp op, OpAdaptor adaptor,
2566 ConversionPatternRewriter &rewriter)
const override {
2574 auto unpackedPred = adaptor.getPredicateAttr().getValue();
2575 sim::QueueCmpPredicate queuePred;
2576 switch (unpackedPred) {
2577 case circt::moore::UArrayCmpPredicate::eq:
2578 queuePred = sim::QueueCmpPredicate::eq;
2580 case circt::moore::UArrayCmpPredicate::ne:
2581 queuePred = sim::QueueCmpPredicate::ne;
2585 "All unpacked array comparison predicates should be handled");
2588 auto cmpPred = sim::QueueCmpPredicateAttr::get(getContext(), queuePred);
2590 rewriter.replaceOpWithNewOp<sim::QueueCmpOp>(op, cmpPred, adaptor.getLhs(),
2596struct QueueFromUnpackedArrayOpConversion
2598 using OpConversionPattern::OpConversionPattern;
2601 matchAndRewrite(QueueFromUnpackedArrayOp op, OpAdaptor adaptor,
2602 ConversionPatternRewriter &rewriter)
const override {
2603 rewriter.replaceOpWithNewOp<sim::QueueFromArrayOp>(
2604 op, getTypeConverter()->convertType(op.getResult().getType()),
2605 adaptor.getInput());
2611 using OpConversionPattern::OpConversionPattern;
2614 matchAndRewrite(QueueConcatOp op, OpAdaptor adaptor,
2615 ConversionPatternRewriter &rewriter)
const override {
2616 rewriter.replaceOpWithNewOp<sim::QueueConcatOp>(
2617 op, getTypeConverter()->convertType(op.getResult().getType()),
2618 adaptor.getInputs());
2624 using OpConversionPattern::OpConversionPattern;
2627 matchAndRewrite(DisplayBIOp op, OpAdaptor adaptor,
2628 ConversionPatternRewriter &rewriter)
const override {
2629 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(
2630 op, adaptor.getMessage());
2642static LogicalResult
convert(StopBIOp op, StopBIOp::Adaptor adaptor,
2643 ConversionPatternRewriter &rewriter) {
2644 rewriter.replaceOpWithNewOp<sim::PauseOp>(op,
false);
2649static LogicalResult
convert(FinishBIOp op, FinishBIOp::Adaptor adaptor,
2650 ConversionPatternRewriter &rewriter) {
2651 rewriter.replaceOpWithNewOp<sim::TerminateOp>(op, op.getExitCode() == 0,
2657static LogicalResult
convert(SeverityBIOp op, SeverityBIOp::Adaptor adaptor,
2658 ConversionPatternRewriter &rewriter) {
2660 std::string severityString;
2662 switch (op.getSeverity()) {
2663 case (Severity::Fatal):
2664 severityString =
"Fatal: ";
2666 case (Severity::Error):
2667 severityString =
"Error: ";
2669 case (Severity::Warning):
2670 severityString =
"Warning: ";
2672 case (Severity::Info):
2673 severityString =
"Info: ";
2678 sim::FormatLiteralOp::create(rewriter, op.getLoc(), severityString);
2679 auto message = sim::FormatStringConcatOp::create(
2680 rewriter, op.getLoc(), ValueRange{prefix, adaptor.getMessage()});
2681 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(op, message);
2687 FinishMessageBIOp::Adaptor adaptor,
2688 ConversionPatternRewriter &rewriter) {
2690 rewriter.eraseOp(op);
2699static LogicalResult
convert(TimeBIOp op, TimeBIOp::Adaptor adaptor,
2700 ConversionPatternRewriter &rewriter) {
2701 rewriter.replaceOpWithNewOp<llhd::CurrentTimeOp>(op);
2706static LogicalResult
convert(LogicToTimeOp op, LogicToTimeOp::Adaptor adaptor,
2707 ConversionPatternRewriter &rewriter) {
2708 rewriter.replaceOpWithNewOp<llhd::IntToTimeOp>(op, adaptor.getInput());
2713static LogicalResult
convert(TimeToLogicOp op, TimeToLogicOp::Adaptor adaptor,
2714 ConversionPatternRewriter &rewriter) {
2715 rewriter.replaceOpWithNewOp<llhd::TimeToIntOp>(op, adaptor.getInput());
2724 const TypeConverter &converter) {
2725 target.addIllegalDialect<MooreDialect>();
2726 target.addLegalDialect<comb::CombDialect>();
2727 target.addLegalDialect<hw::HWDialect>();
2728 target.addLegalDialect<seq::SeqDialect>();
2729 target.addLegalDialect<llhd::LLHDDialect>();
2730 target.addLegalDialect<ltl::LTLDialect>();
2731 target.addLegalDialect<mlir::BuiltinDialect>();
2732 target.addLegalDialect<mlir::math::MathDialect>();
2733 target.addLegalDialect<sim::SimDialect>();
2734 target.addLegalDialect<mlir::LLVM::LLVMDialect>();
2735 target.addLegalDialect<verif::VerifDialect>();
2736 target.addLegalDialect<arith::ArithDialect>();
2738 target.addLegalOp<debug::ScopeOp>();
2740 target.addDynamicallyLegalOp<scf::YieldOp, func::CallOp, func::ReturnOp,
2741 UnrealizedConversionCastOp, hw::OutputOp,
2742 hw::InstanceOp, debug::ArrayOp, debug::StructOp,
2744 [&](Operation *op) {
return converter.isLegal(op); });
2746 target.addDynamicallyLegalOp<scf::IfOp, scf::ForOp, scf::ExecuteRegionOp,
2747 scf::WhileOp, scf::ForallOp>([&](Operation *op) {
2748 return converter.isLegal(op) && !op->getParentOfType<llhd::ProcessOp>();
2751 target.addDynamicallyLegalOp<func::FuncOp>([&](func::FuncOp op) {
2752 return converter.isSignatureLegal(op.getFunctionType());
2756 return converter.isSignatureLegal(op.getModuleType().getFuncType()) &&
2757 converter.isLegal(&op.getBody());
2762 typeConverter.addConversion([&](IntType type) {
2763 return IntegerType::get(type.getContext(), type.getWidth());
2766 typeConverter.addConversion([&](RealType type) -> mlir::Type {
2767 MLIRContext *ctx = type.getContext();
2768 switch (type.getWidth()) {
2769 case moore::RealWidth::f32:
2770 return mlir::Float32Type::get(ctx);
2771 case moore::RealWidth::f64:
2772 return mlir::Float64Type::get(ctx);
2776 typeConverter.addConversion(
2777 [&](TimeType type) {
return llhd::TimeType::get(type.getContext()); });
2779 typeConverter.addConversion([&](FormatStringType type) {
2780 return sim::FormatStringType::get(type.getContext());
2783 typeConverter.addConversion([&](StringType type) {
2784 return sim::DynamicStringType::get(type.getContext());
2787 typeConverter.addConversion([&](QueueType type) {
2788 return sim::QueueType::get(type.getContext(),
2789 typeConverter.convertType(type.getElementType()),
2793 typeConverter.addConversion([&](ArrayType type) -> std::optional<Type> {
2794 if (
auto elementType = typeConverter.convertType(type.getElementType()))
2795 return hw::ArrayType::get(
elementType, type.getSize());
2802 typeConverter.addConversion(
2803 [&](UnpackedArrayType type) -> std::optional<Type> {
2804 if (
auto elementType = typeConverter.convertType(type.getElementType()))
2805 return hw::ArrayType::get(
elementType, type.getSize());
2809 typeConverter.addConversion([&](OpenArrayType type) -> std::optional<Type> {
2810 return LLVM::LLVMPointerType::get(type.getContext());
2813 typeConverter.addConversion(
2814 [&](OpenUnpackedArrayType type) -> std::optional<Type> {
2815 return LLVM::LLVMPointerType::get(type.getContext());
2818 typeConverter.addConversion([&](StructType type) -> std::optional<Type> {
2819 SmallVector<hw::StructType::FieldInfo> fields;
2820 for (
auto field : type.getMembers()) {
2821 hw::StructType::FieldInfo info;
2822 info.type = typeConverter.convertType(field.type);
2825 info.name = field.name;
2826 fields.push_back(info);
2828 return hw::StructType::get(type.getContext(), fields);
2836 typeConverter.addConversion(
2837 [&](UnpackedStructType type) -> std::optional<Type> {
2838 SmallVector<hw::StructType::FieldInfo> fields;
2839 for (
auto field : type.getMembers()) {
2840 hw::StructType::FieldInfo info;
2841 info.type = typeConverter.convertType(field.type);
2844 info.name = field.name;
2845 fields.push_back(info);
2847 return hw::StructType::get(type.getContext(), fields);
2851 typeConverter.addConversion([&](UnionType type) -> std::optional<Type> {
2852 SmallVector<hw::UnionType::FieldInfo> fields;
2853 for (
auto field : type.getMembers()) {
2854 hw::UnionType::FieldInfo info;
2855 info.type = typeConverter.convertType(field.type);
2858 info.name = field.name;
2860 fields.push_back(info);
2862 auto result = hw::UnionType::get(type.getContext(), fields);
2867 typeConverter.addConversion(
2868 [&](UnpackedUnionType type) -> std::optional<Type> {
2869 SmallVector<hw::UnionType::FieldInfo> fields;
2870 for (
auto field : type.getMembers()) {
2871 hw::UnionType::FieldInfo info;
2872 info.type = typeConverter.convertType(field.type);
2875 info.name = field.name;
2877 fields.push_back(info);
2879 return hw::UnionType::get(type.getContext(), fields);
2883 typeConverter.addConversion([&](ChandleType type) -> std::optional<Type> {
2884 return LLVM::LLVMPointerType::get(type.getContext());
2888 typeConverter.addConversion(
2889 [](LLVM::LLVMPointerType t) -> std::optional<Type> {
return t; });
2892 typeConverter.addConversion([&](ClassHandleType type) -> std::optional<Type> {
2893 return LLVM::LLVMPointerType::get(type.getContext());
2896 typeConverter.addConversion([&](RefType type) -> std::optional<Type> {
2897 if (isa<OpenArrayType, OpenUnpackedArrayType>(type.getNestedType()))
2898 return LLVM::LLVMPointerType::get(type.getContext());
2899 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
2900 return llhd::RefType::get(innerType);
2905 typeConverter.addConversion([](IntegerType type) {
return type; });
2906 typeConverter.addConversion([](FloatType type) {
return type; });
2907 typeConverter.addConversion([](sim::DynamicStringType type) {
return type; });
2908 typeConverter.addConversion([](llhd::TimeType type) {
return type; });
2909 typeConverter.addConversion([](debug::ArrayType type) {
return type; });
2910 typeConverter.addConversion([](debug::ScopeType type) {
return type; });
2911 typeConverter.addConversion([](debug::StructType type) {
return type; });
2913 typeConverter.addConversion([&](llhd::RefType type) -> std::optional<Type> {
2914 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
2915 return llhd::RefType::get(innerType);
2919 typeConverter.addConversion([&](hw::ArrayType type) -> std::optional<Type> {
2920 if (
auto elementType = typeConverter.convertType(type.getElementType()))
2921 return hw::ArrayType::get(
elementType, type.getNumElements());
2925 typeConverter.addConversion([&](hw::StructType type) -> std::optional<Type> {
2926 SmallVector<hw::StructType::FieldInfo> fields;
2927 for (
auto field : type.getElements()) {
2928 hw::StructType::FieldInfo info;
2929 info.type = typeConverter.convertType(field.type);
2932 info.name = field.name;
2933 fields.push_back(info);
2935 return hw::StructType::get(type.getContext(), fields);
2938 typeConverter.addConversion([&](hw::UnionType type) -> std::optional<Type> {
2939 SmallVector<hw::UnionType::FieldInfo> fields;
2940 for (
auto field : type.getElements()) {
2941 hw::UnionType::FieldInfo info;
2942 info.type = typeConverter.convertType(field.type);
2945 info.name = field.name;
2946 info.offset = field.offset;
2947 fields.push_back(info);
2949 return hw::UnionType::get(type.getContext(), fields);
2952 typeConverter.addTargetMaterialization(
2953 [&](mlir::OpBuilder &builder, mlir::Type resultType,
2954 mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
2955 if (inputs.size() != 1 || !inputs[0])
2957 return UnrealizedConversionCastOp::create(builder, loc, resultType,
2962 typeConverter.addSourceMaterialization(
2963 [&](mlir::OpBuilder &builder, mlir::Type resultType,
2964 mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
2965 if (inputs.size() != 1)
2967 return UnrealizedConversionCastOp::create(builder, loc, resultType,
2974 TypeConverter &typeConverter,
2975 ClassTypeCache &classCache) {
2981 patterns.add<ClassPropertyRefOpConversion>(typeConverter,
2982 patterns.getContext(), classCache);
2986 ClassUpcastOpConversion,
2988 VariableOpConversion,
2992 ConversionOpConversion,
2993 BitcastConversion<PackedToSBVOp>,
2994 BitcastConversion<SBVToPackedOp>,
2995 NoOpConversion<LogicToIntOp>,
2996 NoOpConversion<IntToLogicOp>,
2997 NoOpConversion<ToBuiltinIntOp>,
2998 NoOpConversion<FromBuiltinIntOp>,
3002 SIntToRealOpConversion,
3003 UIntToRealOpConversion,
3004 IntToStringOpConversion,
3005 RealToIntOpConversion,
3011 ReplicateOpConversion,
3013 ExtractOpConversion,
3014 DynExtractOpConversion,
3015 DynExtractRefOpConversion,
3017 StructExtractOpConversion,
3018 StructExtractRefOpConversion,
3019 ExtractRefOpConversion,
3020 StructCreateOpConversion,
3021 UnionCreateOpConversion,
3022 UnionExtractOpConversion,
3023 UnionExtractRefOpConversion,
3024 ConditionalOpConversion,
3025 ArrayCreateOpConversion,
3028 ConstantStringOpConv,
3031 ReduceAndOpConversion,
3032 ReduceOrOpConversion,
3033 ReduceXorOpConversion,
3034 BoolCastOpConversion,
3039 BinaryOpConversion<AddOp, comb::AddOp>,
3040 BinaryOpConversion<SubOp, comb::SubOp>,
3041 BinaryOpConversion<MulOp, comb::MulOp>,
3042 BinaryOpConversion<DivUOp, comb::DivUOp>,
3043 BinaryOpConversion<DivSOp, comb::DivSOp>,
3044 BinaryOpConversion<ModUOp, comb::ModUOp>,
3045 BinaryOpConversion<ModSOp, comb::ModSOp>,
3046 BinaryOpConversion<AndOp, comb::AndOp>,
3047 BinaryOpConversion<OrOp, comb::OrOp>,
3048 BinaryOpConversion<XorOp, comb::XorOp>,
3051 NegRealOpConversion,
3054 BinaryRealOpConversion<AddRealOp, arith::AddFOp>,
3055 BinaryRealOpConversion<SubRealOp, arith::SubFOp>,
3056 BinaryRealOpConversion<DivRealOp, arith::DivFOp>,
3057 BinaryRealOpConversion<MulRealOp, arith::MulFOp>,
3058 BinaryRealOpConversion<PowRealOp, math::PowFOp>,
3061 PowUOpConversion, PowSOpConversion,
3064 ICmpOpConversion<UltOp, ICmpPredicate::ult>,
3065 ICmpOpConversion<SltOp, ICmpPredicate::slt>,
3066 ICmpOpConversion<UleOp, ICmpPredicate::ule>,
3067 ICmpOpConversion<SleOp, ICmpPredicate::sle>,
3068 ICmpOpConversion<UgtOp, ICmpPredicate::ugt>,
3069 ICmpOpConversion<SgtOp, ICmpPredicate::sgt>,
3070 ICmpOpConversion<UgeOp, ICmpPredicate::uge>,
3071 ICmpOpConversion<SgeOp, ICmpPredicate::sge>,
3072 ICmpOpConversion<EqOp, ICmpPredicate::eq>,
3073 ICmpOpConversion<NeOp, ICmpPredicate::ne>,
3074 ICmpOpConversion<CaseEqOp, ICmpPredicate::ceq>,
3075 ICmpOpConversion<CaseNeOp, ICmpPredicate::cne>,
3076 ICmpOpConversion<WildcardEqOp, ICmpPredicate::weq>,
3077 ICmpOpConversion<WildcardNeOp, ICmpPredicate::wne>,
3078 FCmpOpConversion<NeRealOp, arith::CmpFPredicate::ONE>,
3079 FCmpOpConversion<FltOp, arith::CmpFPredicate::OLT>,
3080 FCmpOpConversion<FleOp, arith::CmpFPredicate::OLE>,
3081 FCmpOpConversion<FgtOp, arith::CmpFPredicate::OGT>,
3082 FCmpOpConversion<FgeOp, arith::CmpFPredicate::OGE>,
3083 FCmpOpConversion<EqRealOp, arith::CmpFPredicate::OEQ>,
3084 CaseXZEqOpConversion<CaseZEqOp, true>,
3085 CaseXZEqOpConversion<CaseXZEqOp, false>,
3088 SVModuleOpConversion,
3089 InstanceOpConversion,
3090 ProcedureOpConversion,
3091 WaitEventOpConversion,
3099 AssignOpConversion<ContinuousAssignOp>,
3100 AssignOpConversion<DelayedContinuousAssignOp>,
3101 AssignOpConversion<BlockingAssignOp>,
3102 AssignOpConversion<NonBlockingAssignOp>,
3103 AssignOpConversion<DelayedNonBlockingAssignOp>,
3104 AssignedVariableOpConversion,
3107 HWInstanceOpConversion,
3110 UnrealizedConversionCastConversion,
3111 InPlaceOpConversion<debug::ArrayOp>,
3112 InPlaceOpConversion<debug::StructOp>,
3113 InPlaceOpConversion<debug::VariableOp>,
3116 AssertLikeOpConversion<AssertOp, verif::AssertOp>,
3117 AssertLikeOpConversion<AssumeOp, verif::AssumeOp>,
3118 AssertLikeOpConversion<CoverOp, verif::CoverOp>,
3121 FormatLiteralOpConversion,
3122 FormatConcatOpConversion,
3123 FormatHierPathOpConversion,
3124 FormatIntOpConversion,
3125 FormatRealOpConversion,
3126 DisplayBIOpConversion,
3129 StringLenOpConversion,
3130 StringConcatOpConversion,
3131 StringGetOpConversion,
3134 QueueSizeBIOpConversion,
3135 QueuePushBackOpConversion,
3136 QueuePushFrontOpConversion,
3137 QueuePopBackOpConversion,
3138 QueuePopFrontOpConversion,
3139 QueueDeleteOpConversion,
3140 QueueInsertOpConversion,
3141 QueueClearOpConversion,
3142 DynQueueExtractOpConversion,
3143 QueueResizeOpConversion,
3144 QueueSetOpConversion,
3145 QueueCmpOpConversion,
3146 QueueFromUnpackedArrayOpConversion,
3147 QueueConcatOpConversion
3148 >(typeConverter,
patterns.getContext());
3168 mlir::populateAnyFunctionOpInterfaceTypeConversionPattern(
patterns,
3170 hw::populateHWModuleLikeTypeConversionPattern(
3171 hw::HWModuleOp::getOperationName(),
patterns, typeConverter);
3172 populateSCFToControlFlowConversionPatterns(
patterns);
3181struct MooreToCorePass
3182 :
public circt::impl::ConvertMooreToCoreBase<MooreToCorePass> {
3183 void runOnOperation()
override;
3189 return std::make_unique<MooreToCorePass>();
3193void MooreToCorePass::runOnOperation() {
3194 MLIRContext &
context = getContext();
3195 ModuleOp
module = getOperation();
3196 ClassTypeCache classCache;
3198 IRRewriter rewriter(module);
3199 (void)mlir::eraseUnreachableBlocks(rewriter, module->getRegions());
3201 TypeConverter typeConverter;
3204 ConversionTarget target(
context);
3209 mlir::cf::populateCFStructuralTypeConversionsAndLegality(typeConverter,
3212 if (failed(applyFullConversion(module, target, std::move(
patterns))))
3213 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.