21#include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h"
22#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
23#include "mlir/Dialect/ControlFlow/Transforms/StructuralTypeConversions.h"
24#include "mlir/Dialect/Func/IR/FuncOps.h"
25#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
26#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
27#include "mlir/Dialect/Math/IR/Math.h"
28#include "mlir/Dialect/SCF/IR/SCF.h"
29#include "mlir/IR/BuiltinDialect.h"
30#include "mlir/IR/Iterators.h"
31#include "mlir/Interfaces/SideEffectInterfaces.h"
32#include "mlir/Pass/Pass.h"
33#include "mlir/Transforms/DialectConversion.h"
34#include "mlir/Transforms/RegionUtils.h"
35#include "llvm/ADT/TypeSwitch.h"
36#include "llvm/IR/DerivedTypes.h"
39#define GEN_PASS_DEF_CONVERTMOORETOCORE
40#include "circt/Conversion/Passes.h.inc"
47using comb::ICmpPredicate;
48using llvm::SmallDenseSet;
53struct ClassTypeCache {
54 struct ClassStructInfo {
55 LLVM::LLVMStructType classBody;
58 DenseMap<StringRef, SmallVector<unsigned, 2>> propertyPath;
62 void setFieldPath(StringRef propertyName, ArrayRef<unsigned> path) {
63 this->propertyPath[propertyName] =
64 SmallVector<unsigned, 2>(path.begin(), path.end());
68 std::optional<ArrayRef<unsigned>>
69 getFieldPath(StringRef propertySym)
const {
70 if (
auto prop = this->propertyPath.find(propertySym);
71 prop != this->propertyPath.end())
72 return ArrayRef<unsigned>(prop->second);
79 void setClassInfo(SymbolRefAttr classSym,
const ClassStructInfo &
info) {
80 auto &dst = classToStructMap[classSym];
85 std::optional<ClassStructInfo> getStructInfo(SymbolRefAttr classSym)
const {
86 if (
auto it = classToStructMap.find(classSym); it != classToStructMap.end())
95 DenseMap<Attribute, ClassStructInfo> classToStructMap;
99static LLVM::LLVMFuncOp getOrCreateMalloc(ModuleOp mod, OpBuilder &b) {
100 if (
auto f = mod.lookupSymbol<LLVM::LLVMFuncOp>(
"malloc"))
103 OpBuilder::InsertionGuard g(b);
104 b.setInsertionPointToStart(mod.getBody());
106 auto i64Ty = IntegerType::get(mod.getContext(), 64);
107 auto ptrTy = LLVM::LLVMPointerType::get(mod.getContext());
108 auto fnTy = LLVM::LLVMFunctionType::get(ptrTy, {i64Ty},
false);
110 auto fn = LLVM::LLVMFuncOp::create(b, mod.getLoc(),
"malloc", fnTy);
112 fn.setLinkage(LLVM::Linkage::External);
118static LLVM::LLVMStructType getOrCreateOpaqueStruct(MLIRContext *ctx,
119 SymbolRefAttr className) {
120 return LLVM::LLVMStructType::getIdentified(ctx, className.getRootReference());
123static LogicalResult resolveClassStructBody(ClassDeclOp op,
124 TypeConverter
const &typeConverter,
125 ClassTypeCache &cache) {
127 auto classSym = SymbolRefAttr::get(op.getSymNameAttr());
128 auto structInfo = cache.getStructInfo(classSym);
134 ClassTypeCache::ClassStructInfo structBody;
135 SmallVector<Type> structBodyMembers;
138 unsigned derivedStartIdx = 0;
140 if (
auto baseClass = op.getBaseAttr()) {
142 ModuleOp mod = op->getParentOfType<ModuleOp>();
143 auto *opSym = mod.lookupSymbol(baseClass);
144 auto classDeclOp = cast<ClassDeclOp>(opSym);
146 if (failed(resolveClassStructBody(classDeclOp, typeConverter, cache)))
150 auto baseClassStruct = cache.getStructInfo(baseClass);
151 structBodyMembers.push_back(baseClassStruct->classBody);
155 for (
auto &kv : baseClassStruct->propertyPath) {
156 SmallVector<unsigned, 2> path;
158 path.append(kv.second.begin(), kv.second.end());
159 structBody.setFieldPath(kv.first, path);
164 unsigned iterator = derivedStartIdx;
165 auto &block = op.getBody().front();
166 for (Operation &child : block) {
167 if (
auto prop = dyn_cast<ClassPropertyDeclOp>(child)) {
168 Type mooreTy = prop.getPropertyType();
169 Type llvmTy = typeConverter.convertType(mooreTy);
171 return prop.emitOpError()
172 <<
"failed to convert property type " << mooreTy;
174 structBodyMembers.push_back(llvmTy);
177 SmallVector<unsigned, 2> path{iterator};
178 structBody.setFieldPath(prop.getSymName(), path);
184 auto llvmStructTy = getOrCreateOpaqueStruct(op.getContext(), classSym);
186 if (!structBodyMembers.empty() &&
187 failed(llvmStructTy.setBody(structBodyMembers,
false)))
188 return op.emitOpError() <<
"Failed to set LLVM Struct body";
190 structBody.classBody = llvmStructTy;
191 cache.setClassInfo(classSym, structBody);
197static LogicalResult resolveClassStructBody(ModuleOp mod, SymbolRefAttr op,
198 TypeConverter
const &typeConverter,
199 ClassTypeCache &cache) {
200 auto classDeclOp = cast<ClassDeclOp>(*mod.lookupSymbol(op));
201 return resolveClassStructBody(classDeclOp, typeConverter, cache);
208static Value adjustIntegerWidth(OpBuilder &builder, Value value,
209 uint32_t targetWidth, Location loc) {
210 uint32_t intWidth = value.getType().getIntOrFloatBitWidth();
211 if (intWidth == targetWidth)
214 if (intWidth < targetWidth) {
216 builder, loc, builder.getIntegerType(targetWidth - intWidth), 0);
217 return comb::ConcatOp::create(builder, loc, ValueRange{zeroExt, value});
221 intWidth - targetWidth);
223 builder, loc, builder.getIntegerType(intWidth - targetWidth), 0);
224 Value isZero = comb::ICmpOp::create(builder, loc, comb::ICmpPredicate::eq, hi,
228 builder.getIntegerType(targetWidth), -1);
229 return comb::MuxOp::create(builder, loc, isZero, lo, max,
false);
236 size_t resultNum = 0;
237 auto moduleTy = op.getModuleType();
238 SmallVector<hw::PortInfo> ports;
239 ports.reserve(moduleTy.getNumPorts());
241 for (
auto port : moduleTy.getPorts()) {
242 Type portTy = typeConverter.convertType(port.type);
243 if (port.dir == hw::ModulePort::Direction::Output) {
245 hw::PortInfo({{port.name, portTy, port.dir}, resultNum++, {}}));
253 hw::PortInfo({{port.name, portTy, port.dir}, inputNum++, {}}));
265 using OpConversionPattern::OpConversionPattern;
268 matchAndRewrite(SVModuleOp op, OpAdaptor adaptor,
269 ConversionPatternRewriter &rewriter)
const override {
270 rewriter.setInsertionPoint(op);
274 hw::HWModuleOp::create(rewriter, op.getLoc(), op.getSymNameAttr(),
275 getModulePortInfo(*typeConverter, op));
278 SymbolTable::setSymbolVisibility(hwModuleOp,
279 SymbolTable::getSymbolVisibility(op));
280 rewriter.eraseBlock(hwModuleOp.getBodyBlock());
282 rewriter.convertRegionTypes(&op.getBodyRegion(), *typeConverter)))
284 rewriter.inlineRegionBefore(op.getBodyRegion(), hwModuleOp.getBodyRegion(),
285 hwModuleOp.getBodyRegion().end());
288 rewriter.eraseOp(op);
294 using OpConversionPattern::OpConversionPattern;
297 matchAndRewrite(OutputOp op, OpAdaptor adaptor,
298 ConversionPatternRewriter &rewriter)
const override {
299 rewriter.replaceOpWithNewOp<hw::OutputOp>(op, adaptor.getOperands());
305 using OpConversionPattern::OpConversionPattern;
308 matchAndRewrite(InstanceOp op, OpAdaptor adaptor,
309 ConversionPatternRewriter &rewriter)
const override {
310 auto instName = op.getInstanceNameAttr();
311 auto moduleName = op.getModuleNameAttr();
314 rewriter.setInsertionPoint(op);
315 auto instOp = hw::InstanceOp::create(
316 rewriter, op.getLoc(), op.getResultTypes(), instName, moduleName,
317 op.getInputs(), op.getInputNamesAttr(), op.getOutputNamesAttr(),
318 rewriter.getArrayAttr({}),
nullptr,
322 op.replaceAllUsesWith(instOp.getResults());
323 rewriter.eraseOp(op);
328static void getValuesToObserve(Region *region,
329 function_ref<
void(Value)> setInsertionPoint,
330 const TypeConverter *typeConverter,
331 ConversionPatternRewriter &rewriter,
332 SmallVector<Value> &observeValues) {
333 SmallDenseSet<Value> alreadyObserved;
334 Location loc = region->getLoc();
336 auto probeIfSignal = [&](Value value) -> Value {
337 if (!isa<llhd::RefType>(value.getType()))
339 return llhd::ProbeOp::create(rewriter, loc, value);
342 region->getParentOp()->walk<WalkOrder::PreOrder, ForwardDominanceIterator<>>(
343 [&](Operation *operation) {
344 for (
auto value : operation->getOperands()) {
345 if (isa<BlockArgument>(value))
346 value = rewriter.getRemappedValue(value);
348 if (region->isAncestor(value.getParentRegion()))
350 if (
auto *defOp = value.getDefiningOp();
351 defOp && defOp->hasTrait<OpTrait::ConstantLike>())
353 if (!alreadyObserved.insert(value).second)
356 OpBuilder::InsertionGuard g(rewriter);
357 if (
auto remapped = rewriter.getRemappedValue(value)) {
358 setInsertionPoint(remapped);
359 observeValues.push_back(probeIfSignal(remapped));
361 setInsertionPoint(value);
362 auto type = typeConverter->convertType(value.getType());
363 auto converted = typeConverter->materializeTargetConversion(
364 rewriter, loc, type, value);
365 observeValues.push_back(probeIfSignal(converted));
372 using OpConversionPattern::OpConversionPattern;
375 matchAndRewrite(ProcedureOp op, OpAdaptor adaptor,
376 ConversionPatternRewriter &rewriter)
const override {
378 SmallVector<Value> observedValues;
379 if (op.getKind() == ProcedureKind::AlwaysComb ||
380 op.getKind() == ProcedureKind::AlwaysLatch) {
381 auto setInsertionPoint = [&](Value value) {
382 rewriter.setInsertionPoint(op);
384 getValuesToObserve(&op.getBody(), setInsertionPoint, typeConverter,
385 rewriter, observedValues);
388 auto loc = op.getLoc();
389 if (failed(rewriter.convertRegionTypes(&op.getBody(), *typeConverter)))
394 if (op.getKind() == ProcedureKind::Initial ||
395 op.getKind() == ProcedureKind::Final) {
397 if (op.getKind() == ProcedureKind::Initial)
398 newOp = llhd::ProcessOp::create(rewriter, loc, TypeRange{});
400 newOp = llhd::FinalOp::create(rewriter, loc);
401 auto &body = newOp->getRegion(0);
402 rewriter.inlineRegionBefore(op.getBody(), body, body.end());
404 llvm::make_early_inc_range(body.getOps<ReturnOp>())) {
405 rewriter.setInsertionPoint(returnOp);
406 rewriter.replaceOpWithNewOp<llhd::HaltOp>(returnOp, ValueRange{});
408 rewriter.eraseOp(op);
413 auto newOp = llhd::ProcessOp::create(rewriter, loc, TypeRange{});
418 rewriter.createBlock(&newOp.getBody());
419 auto *block = &op.getBody().front();
420 cf::BranchOp::create(rewriter, loc, block);
421 rewriter.inlineRegionBefore(op.getBody(), newOp.getBody(),
422 newOp.getBody().end());
430 if (op.getKind() == ProcedureKind::AlwaysComb ||
431 op.getKind() == ProcedureKind::AlwaysLatch) {
432 Block *waitBlock = rewriter.createBlock(&newOp.getBody());
433 llhd::WaitOp::create(rewriter, loc, ValueRange{}, Value(), observedValues,
434 ValueRange{}, block);
441 for (
auto returnOp :
llvm::make_early_inc_range(newOp.getOps<ReturnOp>())) {
442 rewriter.setInsertionPoint(returnOp);
443 cf::BranchOp::create(rewriter, loc, block);
444 rewriter.eraseOp(returnOp);
447 rewriter.eraseOp(op);
453 using OpConversionPattern::OpConversionPattern;
456 matchAndRewrite(WaitEventOp op, OpAdaptor adaptor,
457 ConversionPatternRewriter &rewriter)
const override {
491 rewriter.splitBlock(op->getBlock(), ++Block::iterator(op));
497 if (op.getBody().front().empty()) {
500 rewriter.replaceOpWithNewOp<llhd::HaltOp>(op, ValueRange{});
504 auto *waitBlock = rewriter.createBlock(resumeBlock);
505 auto *checkBlock = rewriter.createBlock(resumeBlock);
507 auto loc = op.getLoc();
508 rewriter.setInsertionPoint(op);
509 cf::BranchOp::create(rewriter, loc, waitBlock);
519 SmallVector<Value> valuesBefore;
520 rewriter.setInsertionPointToEnd(waitBlock);
521 auto clonedOp = cast<WaitEventOp>(rewriter.clone(*op));
522 bool allDetectsAreAnyChange =
true;
524 llvm::make_early_inc_range(clonedOp.getOps<DetectEventOp>())) {
525 if (detectOp.getEdge() != Edge::AnyChange || detectOp.getCondition())
526 allDetectsAreAnyChange =
false;
527 valuesBefore.push_back(detectOp.getInput());
528 rewriter.eraseOp(detectOp);
534 SmallVector<Value> observeValues;
535 auto setInsertionPointAfterDef = [&](Value value) {
536 if (
auto *op = value.getDefiningOp())
537 rewriter.setInsertionPointAfter(op);
538 if (
auto arg = dyn_cast<BlockArgument>(value))
539 rewriter.setInsertionPointToStart(value.getParentBlock());
542 getValuesToObserve(&clonedOp.getBody(), setInsertionPointAfterDef,
543 typeConverter, rewriter, observeValues);
548 auto waitOp = llhd::WaitOp::create(rewriter, loc, ValueRange{}, Value(),
549 observeValues, ValueRange{}, checkBlock);
550 rewriter.inlineBlockBefore(&clonedOp.getBody().front(), waitOp);
551 rewriter.eraseOp(clonedOp);
555 SmallVector<DetectEventOp> detectOps(op.getBody().getOps<DetectEventOp>());
556 rewriter.inlineBlockBefore(&op.getBody().front(), checkBlock,
558 rewriter.eraseOp(op);
562 auto computeTrigger = [&](Value before, Value after, Edge edge) -> Value {
563 assert(before.getType() == after.getType() &&
564 "mismatched types after clone op");
565 auto beforeType = cast<IntType>(before.getType());
569 if (beforeType.getWidth() != 1 && edge != Edge::AnyChange) {
570 constexpr int LSB = 0;
572 IntType::get(rewriter.getContext(), 1, beforeType.getDomain());
574 moore::ExtractOp::create(rewriter, loc, beforeType, before, LSB);
575 after = moore::ExtractOp::create(rewriter, loc, beforeType, after, LSB);
578 auto intType = rewriter.getIntegerType(beforeType.getWidth());
579 before = typeConverter->materializeTargetConversion(rewriter, loc,
581 after = typeConverter->materializeTargetConversion(rewriter, loc, intType,
584 if (edge == Edge::AnyChange)
585 return comb::ICmpOp::create(rewriter, loc, ICmpPredicate::ne, before,
588 SmallVector<Value> disjuncts;
591 if (edge == Edge::PosEdge || edge == Edge::BothEdges) {
593 comb::XorOp::create(rewriter, loc, before, trueVal,
true);
595 comb::AndOp::create(rewriter, loc, notOldVal, after,
true);
596 disjuncts.push_back(posedge);
599 if (edge == Edge::NegEdge || edge == Edge::BothEdges) {
601 comb::XorOp::create(rewriter, loc, after, trueVal,
true);
603 comb::AndOp::create(rewriter, loc, before, notCurrVal,
true);
604 disjuncts.push_back(posedge);
607 return rewriter.createOrFold<
comb::OrOp>(loc, disjuncts,
true);
614 SmallVector<Value> triggers;
615 for (
auto [detectOp, before] :
llvm::zip(detectOps, valuesBefore)) {
616 if (!allDetectsAreAnyChange) {
617 if (!isa<IntType>(before.getType()))
618 return detectOp->emitError() <<
"requires int operand";
620 rewriter.setInsertionPoint(detectOp);
622 computeTrigger(before, detectOp.getInput(), detectOp.getEdge());
623 if (detectOp.getCondition()) {
624 auto condition = typeConverter->materializeTargetConversion(
625 rewriter, loc, rewriter.getI1Type(), detectOp.getCondition());
627 comb::AndOp::create(rewriter, loc, trigger, condition,
true);
629 triggers.push_back(trigger);
632 rewriter.eraseOp(detectOp);
635 rewriter.setInsertionPointToEnd(checkBlock);
636 if (triggers.empty()) {
641 cf::BranchOp::create(rewriter, loc, resumeBlock);
647 auto triggered = rewriter.createOrFold<
comb::OrOp>(loc, triggers,
true);
648 cf::CondBranchOp::create(rewriter, loc, triggered, resumeBlock,
657static LogicalResult
convert(WaitDelayOp op, WaitDelayOp::Adaptor adaptor,
658 ConversionPatternRewriter &rewriter) {
660 rewriter.splitBlock(op->getBlock(), ++Block::iterator(op));
661 rewriter.setInsertionPoint(op);
662 rewriter.replaceOpWithNewOp<llhd::WaitOp>(op, ValueRange{},
663 adaptor.getDelay(), ValueRange{},
664 ValueRange{}, resumeBlock);
665 rewriter.setInsertionPointToStart(resumeBlock);
670static LogicalResult
convert(UnreachableOp op, UnreachableOp::Adaptor adaptor,
671 ConversionPatternRewriter &rewriter) {
672 rewriter.replaceOpWithNewOp<llhd::HaltOp>(op, ValueRange{});
681 ConversionPatternRewriter &rewriter) {
683 if (isa<mlir::LLVM::LLVMPointerType>(type))
684 return mlir::LLVM::ZeroOp::create(rewriter, loc, type);
687 if (isa<llhd::TimeType>(type)) {
689 llhd::TimeAttr::get(type.getContext(), 0U, llvm::StringRef(
"ns"), 0, 0);
690 return llhd::ConstantTimeOp::create(rewriter, loc, timeAttr);
694 if (
auto floatType = dyn_cast<FloatType>(type)) {
695 auto floatAttr = rewriter.getFloatAttr(floatType, 0.0);
696 return mlir::arith::ConstantOp::create(rewriter, loc, floatAttr);
700 int64_t width = hw::getBitWidth(type);
708 return rewriter.createOrFold<
hw::BitcastOp>(loc, type, constZero);
711struct ClassPropertyRefOpConversion
713 ClassPropertyRefOpConversion(TypeConverter &tc, MLIRContext *ctx,
714 ClassTypeCache &cache)
718 matchAndRewrite(circt::moore::ClassPropertyRefOp op, OpAdaptor adaptor,
719 ConversionPatternRewriter &rewriter)
const override {
720 Location loc = op.getLoc();
721 MLIRContext *ctx = rewriter.getContext();
724 Type dstTy = getTypeConverter()->convertType(op.getPropertyRef().getType());
726 Value instRef = adaptor.getInstance();
730 cast<circt::moore::ClassHandleType>(op.getInstance().getType());
731 SymbolRefAttr classSym = classRefTy.getClassSym();
732 ModuleOp mod = op->getParentOfType<ModuleOp>();
733 if (failed(resolveClassStructBody(mod, classSym, *typeConverter, cache)))
734 return rewriter.notifyMatchFailure(op,
735 "Could not resolve class struct for " +
736 classSym.getRootReference().str());
738 auto structInfo = cache.getStructInfo(classSym);
739 assert(structInfo &&
"class struct info must exist");
740 auto structTy = structInfo->classBody;
743 auto propSym = op.getProperty();
744 auto pathOpt = structInfo->getFieldPath(propSym);
746 return rewriter.notifyMatchFailure(op,
747 "no GEP path for property " + propSym);
749 auto i32Ty = IntegerType::get(ctx, 32);
750 SmallVector<Value> idxVals;
751 for (
unsigned idx : *pathOpt)
752 idxVals.push_back(LLVM::ConstantOp::create(
753 rewriter, loc, i32Ty, rewriter.getI32IntegerAttr(idx)));
756 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
758 LLVM::GEPOp::create(rewriter, loc, ptrTy, structTy, instRef, idxVals);
761 Value fieldRef = UnrealizedConversionCastOp::create(rewriter, loc, dstTy,
765 rewriter.replaceOp(op, fieldRef);
770 ClassTypeCache &cache;
774 using OpConversionPattern::OpConversionPattern;
777 matchAndRewrite(ClassUpcastOp op, OpAdaptor adaptor,
778 ConversionPatternRewriter &rewriter)
const override {
780 Type dstTy = getTypeConverter()->convertType(op.getResult().getType());
781 Type srcTy = adaptor.getInstance().getType();
784 return rewriter.notifyMatchFailure(op,
"failed to convert result type");
787 if (dstTy == srcTy && isa<LLVM::LLVMPointerType>(srcTy)) {
788 rewriter.replaceOp(op, adaptor.getInstance());
791 return rewriter.notifyMatchFailure(
792 op,
"Upcast applied to non-opaque pointers!");
798 ClassNewOpConversion(TypeConverter &tc, MLIRContext *ctx,
799 ClassTypeCache &cache)
803 matchAndRewrite(ClassNewOp op, OpAdaptor adaptor,
804 ConversionPatternRewriter &rewriter)
const override {
805 Location loc = op.getLoc();
806 MLIRContext *ctx = rewriter.getContext();
808 auto handleTy = cast<ClassHandleType>(op.getResult().getType());
809 auto sym = handleTy.getClassSym();
811 ModuleOp mod = op->getParentOfType<ModuleOp>();
813 if (failed(resolveClassStructBody(mod, sym, *typeConverter, cache)))
814 return op.emitError() <<
"Could not resolve class struct for " << sym;
816 auto structTy = cache.getStructInfo(sym)->classBody;
820 uint64_t byteSize = dl.getTypeSize(structTy);
821 auto i64Ty = IntegerType::get(ctx, 64);
822 auto cSize = LLVM::ConstantOp::create(rewriter, loc, i64Ty,
823 rewriter.getI64IntegerAttr(byteSize));
826 auto mallocFn = getOrCreateMalloc(mod, rewriter);
827 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
829 LLVM::CallOp::create(rewriter, loc, TypeRange{ptrTy},
830 SymbolRefAttr::get(mallocFn), ValueRange{cSize});
834 rewriter.replaceOp(op, call.getResult());
839 ClassTypeCache &cache;
843 ClassDeclOpConversion(TypeConverter &tc, MLIRContext *ctx,
844 ClassTypeCache &cache)
848 matchAndRewrite(ClassDeclOp op, OpAdaptor,
849 ConversionPatternRewriter &rewriter)
const override {
851 if (failed(resolveClassStructBody(op, *typeConverter, cache)))
854 rewriter.eraseOp(op);
859 ClassTypeCache &cache;
863 using OpConversionPattern::OpConversionPattern;
866 matchAndRewrite(VariableOp op, OpAdaptor adaptor,
867 ConversionPatternRewriter &rewriter)
const override {
868 auto loc = op.getLoc();
869 auto resultType = typeConverter->convertType(op.getResult().getType());
871 return rewriter.notifyMatchFailure(op.getLoc(),
"invalid variable type");
874 Value init = adaptor.getInitial();
876 auto elementType = cast<llhd::RefType>(resultType).getNestedType();
882 rewriter.replaceOpWithNewOp<llhd::SignalOp>(op, resultType,
883 op.getNameAttr(), init);
889 using OpConversionPattern::OpConversionPattern;
892 matchAndRewrite(NetOp op, OpAdaptor adaptor,
893 ConversionPatternRewriter &rewriter)
const override {
894 auto loc = op.getLoc();
895 if (op.getKind() != NetKind::Wire)
896 return rewriter.notifyMatchFailure(loc,
"only wire nets supported");
898 auto resultType = typeConverter->convertType(op.getResult().getType());
900 return rewriter.notifyMatchFailure(loc,
"invalid net type");
904 auto elementType = cast<llhd::RefType>(resultType).getNestedType();
912 auto signal = rewriter.replaceOpWithNewOp<llhd::SignalOp>(
913 op, resultType, op.getNameAttr(), init);
915 if (
auto assignedValue = adaptor.getAssignment()) {
916 auto timeAttr = llhd::TimeAttr::get(resultType.getContext(), 0U,
917 llvm::StringRef(
"ns"), 0, 1);
918 auto time = llhd::ConstantTimeOp::create(rewriter, loc, timeAttr);
919 llhd::DriveOp::create(rewriter, loc, signal, assignedValue, time,
932 using OpConversionPattern::OpConversionPattern;
935 matchAndRewrite(ConstantOp op, OpAdaptor adaptor,
936 ConversionPatternRewriter &rewriter)
const override {
938 auto value = op.getValue().toAPInt(
false);
939 auto type = rewriter.getIntegerType(value.getBitWidth());
941 op, type, rewriter.getIntegerAttr(type, value));
947 using OpConversionPattern::OpConversionPattern;
950 matchAndRewrite(ConstantRealOp op, OpAdaptor adaptor,
951 ConversionPatternRewriter &rewriter)
const override {
952 rewriter.replaceOpWithNewOp<arith::ConstantOp>(op, op.getValueAttr());
958 using OpConversionPattern::OpConversionPattern;
961 matchAndRewrite(ConstantTimeOp op, OpAdaptor adaptor,
962 ConversionPatternRewriter &rewriter)
const override {
963 rewriter.replaceOpWithNewOp<llhd::ConstantTimeOp>(
964 op, llhd::TimeAttr::get(op->getContext(), op.getValue(),
965 StringRef(
"fs"), 0, 0));
971 using OpConversionPattern::OpConversionPattern;
973 matchAndRewrite(moore::ConstantStringOp op, OpAdaptor adaptor,
974 ConversionPatternRewriter &rewriter)
const override {
975 const auto resultType =
976 typeConverter->convertType(op.getResult().getType());
977 const auto intType = mlir::cast<IntegerType>(resultType);
979 const auto str = op.getValue();
980 const unsigned byteWidth = intType.getWidth();
981 APInt value(byteWidth, 0);
984 const size_t maxChars =
985 std::min(str.size(),
static_cast<size_t>(byteWidth / 8));
986 for (
size_t i = 0; i < maxChars; i++) {
987 const size_t pos = str.size() - 1 - i;
988 const auto asciiChar =
static_cast<uint8_t
>(str[pos]);
989 value |= APInt(byteWidth, asciiChar) << (8 * i);
993 op, resultType, rewriter.getIntegerAttr(resultType, value));
999 using OpConversionPattern::OpConversionPattern;
1001 matchAndRewrite(ConcatOp op, OpAdaptor adaptor,
1002 ConversionPatternRewriter &rewriter)
const override {
1003 rewriter.replaceOpWithNewOp<
comb::ConcatOp>(op, adaptor.getValues());
1009 using OpConversionPattern::OpConversionPattern;
1011 matchAndRewrite(ReplicateOp op, OpAdaptor adaptor,
1012 ConversionPatternRewriter &rewriter)
const override {
1013 Type resultType = typeConverter->convertType(op.getResult().getType());
1015 rewriter.replaceOpWithNewOp<comb::ReplicateOp>(op, resultType,
1016 adaptor.getValue());
1022 using OpConversionPattern::OpConversionPattern;
1025 matchAndRewrite(ExtractOp op, OpAdaptor adaptor,
1026 ConversionPatternRewriter &rewriter)
const override {
1029 Type resultType = typeConverter->convertType(op.getResult().getType());
1030 Type inputType = adaptor.getInput().getType();
1031 int32_t low = adaptor.getLowBit();
1033 if (isa<IntegerType>(inputType)) {
1034 int32_t inputWidth = inputType.getIntOrFloatBitWidth();
1035 int32_t resultWidth = hw::getBitWidth(resultType);
1036 int32_t high = low + resultWidth;
1038 SmallVector<Value> toConcat;
1041 rewriter, op.getLoc(), APInt(std::min(-low, resultWidth), 0)));
1043 if (low < inputWidth && high > 0) {
1044 int32_t lowIdx = std::max(low, 0);
1047 rewriter.getIntegerType(
1048 std::min(resultWidth, std::min(high, inputWidth) - lowIdx)),
1049 adaptor.getInput(), lowIdx);
1050 toConcat.push_back(middle);
1053 int32_t diff = high - inputWidth;
1057 toConcat.push_back(val);
1062 rewriter.replaceOp(op,
concat);
1066 if (
auto arrTy = dyn_cast<hw::ArrayType>(inputType)) {
1067 int32_t width = llvm::Log2_64_Ceil(arrTy.getNumElements());
1068 int32_t inputWidth = arrTy.getNumElements();
1070 if (
auto resArrTy = dyn_cast<hw::ArrayType>(resultType);
1071 resArrTy && resArrTy != arrTy.getElementType()) {
1072 int32_t elementWidth = hw::getBitWidth(arrTy.getElementType());
1073 if (elementWidth < 0)
1076 int32_t high = low + resArrTy.getNumElements();
1077 int32_t resWidth = resArrTy.getNumElements();
1079 SmallVector<Value> toConcat;
1082 rewriter, op.getLoc(),
1083 APInt(std::min((-low) * elementWidth, resWidth * elementWidth),
1086 op.getLoc(), hw::ArrayType::get(arrTy.getElementType(), -low),
1088 toConcat.push_back(res);
1091 if (low < inputWidth && high > 0) {
1092 int32_t lowIdx = std::max(0, low);
1094 rewriter, op.getLoc(), rewriter.getIntegerType(width), lowIdx);
1098 arrTy.getElementType(),
1099 std::min(resWidth, std::min(inputWidth, high) - lowIdx)),
1100 adaptor.getInput(), lowIdxVal);
1101 toConcat.push_back(middle);
1104 int32_t diff = high - inputWidth;
1107 rewriter, op.getLoc(), APInt(diff * elementWidth, 0));
1109 rewriter, op.getLoc(),
1110 hw::ArrayType::get(arrTy.getElementType(), diff), constZero);
1111 toConcat.push_back(val);
1116 rewriter.replaceOp(op,
concat);
1121 if (low < 0 || low >= inputWidth) {
1122 int32_t bw = hw::getBitWidth(resultType);
1128 rewriter.createOrFold<
hw::BitcastOp>(op.getLoc(), resultType, val);
1129 rewriter.replaceOp(op, bitcast);
1134 rewriter.getIntegerType(width),
1135 adaptor.getLowBit());
1136 rewriter.replaceOpWithNewOp<
hw::ArrayGetOp>(op, adaptor.getInput(), idx);
1145 using OpConversionPattern::OpConversionPattern;
1148 matchAndRewrite(ExtractRefOp op, OpAdaptor adaptor,
1149 ConversionPatternRewriter &rewriter)
const override {
1151 Type resultType = typeConverter->convertType(op.getResult().getType());
1153 cast<llhd::RefType>(adaptor.getInput().getType()).getNestedType();
1155 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1156 int64_t width = hw::getBitWidth(inputType);
1161 rewriter, op.getLoc(),
1162 rewriter.getIntegerType(llvm::Log2_64_Ceil(width)),
1163 adaptor.getLowBit());
1164 rewriter.replaceOpWithNewOp<llhd::SigExtractOp>(
1165 op, resultType, adaptor.getInput(), lowBit);
1169 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1171 rewriter, op.getLoc(),
1172 rewriter.getIntegerType(llvm::Log2_64_Ceil(arrType.getNumElements())),
1173 adaptor.getLowBit());
1177 if (arrType.getElementType() !=
1178 cast<llhd::RefType>(resultType).getNestedType()) {
1179 rewriter.replaceOpWithNewOp<llhd::SigArraySliceOp>(
1180 op, resultType, adaptor.getInput(), lowBit);
1184 rewriter.replaceOpWithNewOp<llhd::SigArrayGetOp>(op, adaptor.getInput(),
1194 using OpConversionPattern::OpConversionPattern;
1197 matchAndRewrite(DynExtractOp op, OpAdaptor adaptor,
1198 ConversionPatternRewriter &rewriter)
const override {
1199 Type resultType = typeConverter->convertType(op.getResult().getType());
1200 Type inputType = adaptor.getInput().getType();
1202 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1203 Value amount = adjustIntegerWidth(rewriter, adaptor.getLowBit(),
1204 intType.getWidth(), op->getLoc());
1205 Value value = comb::ShrUOp::create(rewriter, op->getLoc(),
1206 adaptor.getInput(), amount);
1208 rewriter.replaceOpWithNewOp<
comb::ExtractOp>(op, resultType, value, 0);
1212 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1213 unsigned idxWidth = llvm::Log2_64_Ceil(arrType.getNumElements());
1214 Value idx = adjustIntegerWidth(rewriter, adaptor.getLowBit(), idxWidth,
1217 bool isSingleElementExtract = arrType.getElementType() == resultType;
1219 if (isSingleElementExtract)
1220 rewriter.replaceOpWithNewOp<
hw::ArrayGetOp>(op, adaptor.getInput(),
1224 adaptor.getInput(), idx);
1234 using OpConversionPattern::OpConversionPattern;
1237 matchAndRewrite(DynExtractRefOp op, OpAdaptor adaptor,
1238 ConversionPatternRewriter &rewriter)
const override {
1240 Type resultType = typeConverter->convertType(op.getResult().getType());
1242 cast<llhd::RefType>(adaptor.getInput().getType()).getNestedType();
1244 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1245 int64_t width = hw::getBitWidth(inputType);
1250 adjustIntegerWidth(rewriter, adaptor.getLowBit(),
1251 llvm::Log2_64_Ceil(width), op->getLoc());
1252 rewriter.replaceOpWithNewOp<llhd::SigExtractOp>(
1253 op, resultType, adaptor.getInput(), amount);
1257 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1258 Value idx = adjustIntegerWidth(
1259 rewriter, adaptor.getLowBit(),
1260 llvm::Log2_64_Ceil(arrType.getNumElements()), op->getLoc());
1262 auto resultNestedType = cast<llhd::RefType>(resultType).getNestedType();
1263 bool isSingleElementExtract =
1264 arrType.getElementType() == resultNestedType;
1266 if (isSingleElementExtract)
1267 rewriter.replaceOpWithNewOp<llhd::SigArrayGetOp>(op, adaptor.getInput(),
1270 rewriter.replaceOpWithNewOp<llhd::SigArraySliceOp>(
1271 op, resultType, adaptor.getInput(), idx);
1281 using OpConversionPattern::OpConversionPattern;
1284 matchAndRewrite(ArrayCreateOp op, OpAdaptor adaptor,
1285 ConversionPatternRewriter &rewriter)
const override {
1286 Type resultType = typeConverter->convertType(op.getResult().getType());
1288 adaptor.getElements());
1294 using OpConversionPattern::OpConversionPattern;
1297 matchAndRewrite(StructCreateOp op, OpAdaptor adaptor,
1298 ConversionPatternRewriter &rewriter)
const override {
1299 Type resultType = typeConverter->convertType(op.getResult().getType());
1301 adaptor.getFields());
1307 using OpConversionPattern::OpConversionPattern;
1310 matchAndRewrite(StructExtractOp op, OpAdaptor adaptor,
1311 ConversionPatternRewriter &rewriter)
const override {
1313 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1318struct StructExtractRefOpConversion
1320 using OpConversionPattern::OpConversionPattern;
1323 matchAndRewrite(StructExtractRefOp op, OpAdaptor adaptor,
1324 ConversionPatternRewriter &rewriter)
const override {
1325 rewriter.replaceOpWithNewOp<llhd::SigStructExtractOp>(
1326 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1332 using OpConversionPattern::OpConversionPattern;
1334 matchAndRewrite(ReduceAndOp op, OpAdaptor adaptor,
1335 ConversionPatternRewriter &rewriter)
const override {
1336 Type resultType = typeConverter->convertType(op.getInput().getType());
1339 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::eq,
1340 adaptor.getInput(), max);
1346 using OpConversionPattern::OpConversionPattern;
1348 matchAndRewrite(ReduceOrOp op, OpAdaptor adaptor,
1349 ConversionPatternRewriter &rewriter)
const override {
1350 Type resultType = typeConverter->convertType(op.getInput().getType());
1353 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1354 adaptor.getInput(), zero);
1360 using OpConversionPattern::OpConversionPattern;
1362 matchAndRewrite(ReduceXorOp op, OpAdaptor adaptor,
1363 ConversionPatternRewriter &rewriter)
const override {
1365 rewriter.replaceOpWithNewOp<
comb::ParityOp>(op, adaptor.getInput());
1371 using OpConversionPattern::OpConversionPattern;
1373 matchAndRewrite(BoolCastOp op, OpAdaptor adaptor,
1374 ConversionPatternRewriter &rewriter)
const override {
1375 Type resultType = typeConverter->convertType(op.getInput().getType());
1376 if (isa_and_nonnull<IntegerType>(resultType)) {
1379 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1380 adaptor.getInput(), zero);
1388 using OpConversionPattern::OpConversionPattern;
1390 matchAndRewrite(NotOp op, OpAdaptor adaptor,
1391 ConversionPatternRewriter &rewriter)
const override {
1393 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1396 rewriter.replaceOpWithNewOp<
comb::XorOp>(op, adaptor.getInput(), max);
1402 using OpConversionPattern::OpConversionPattern;
1404 matchAndRewrite(NegOp op, OpAdaptor adaptor,
1405 ConversionPatternRewriter &rewriter)
const override {
1407 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1410 rewriter.replaceOpWithNewOp<
comb::SubOp>(op, zero, adaptor.getInput());
1415template <
typename SourceOp,
typename TargetOp>
1418 using OpAdaptor =
typename SourceOp::Adaptor;
1421 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1422 ConversionPatternRewriter &rewriter)
const override {
1423 rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(),
1424 adaptor.getRhs(),
false);
1429template <
typename SourceOp, ICmpPredicate pred>
1432 using OpAdaptor =
typename SourceOp::Adaptor;
1435 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1436 ConversionPatternRewriter &rewriter)
const override {
1438 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1440 rewriter.replaceOpWithNewOp<comb::ICmpOp>(
1441 op, resultType, pred, adaptor.getLhs(), adaptor.getRhs());
1446template <
typename SourceOp,
bool withoutX>
1449 using OpAdaptor =
typename SourceOp::Adaptor;
1452 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1453 ConversionPatternRewriter &rewriter)
const override {
1459 unsigned bitWidth = op.getLhs().getType().getWidth();
1460 auto ignoredBits = APInt::getZero(bitWidth);
1461 auto detectIgnoredBits = [&](Value value) {
1462 auto constOp = value.getDefiningOp<ConstantOp>();
1465 auto constValue = constOp.getValue();
1467 ignoredBits |= constValue.getZBits();
1469 ignoredBits |= constValue.getUnknownBits();
1471 detectIgnoredBits(op.getLhs());
1472 detectIgnoredBits(op.getRhs());
1476 Value lhs = adaptor.getLhs();
1477 Value rhs = adaptor.getRhs();
1478 if (!ignoredBits.isZero()) {
1479 ignoredBits.flipAllBits();
1481 lhs = rewriter.createOrFold<
comb::AndOp>(op.getLoc(), lhs, maskOp);
1482 rhs = rewriter.createOrFold<
comb::AndOp>(op.getLoc(), rhs, maskOp);
1485 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, ICmpPredicate::ceq, lhs, rhs);
1495 using OpConversionPattern::OpConversionPattern;
1498 matchAndRewrite(ConversionOp op, OpAdaptor adaptor,
1499 ConversionPatternRewriter &rewriter)
const override {
1500 Location loc = op.getLoc();
1501 Type resultType = typeConverter->convertType(op.getResult().getType());
1503 op.emitError(
"conversion result type is not currently supported");
1506 int64_t inputBw = hw::getBitWidth(adaptor.getInput().getType());
1507 int64_t resultBw = hw::getBitWidth(resultType);
1508 if (inputBw == -1 || resultBw == -1)
1512 loc, rewriter.getIntegerType(inputBw), adaptor.getInput());
1513 Value amount = adjustIntegerWidth(rewriter, input, resultBw, loc);
1516 rewriter.createOrFold<
hw::BitcastOp>(loc, resultType, amount);
1517 rewriter.replaceOp(op, result);
1522template <
typename SourceOp>
1525 using OpAdaptor =
typename SourceOp::Adaptor;
1526 using ConversionPattern::typeConverter;
1529 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1530 ConversionPatternRewriter &rewriter)
const override {
1531 auto type = typeConverter->convertType(op.getResult().getType());
1532 if (type == adaptor.getInput().getType())
1533 rewriter.replaceOp(op, adaptor.getInput());
1535 rewriter.replaceOpWithNewOp<
hw::BitcastOp>(op, type, adaptor.getInput());
1541 using OpConversionPattern::OpConversionPattern;
1544 matchAndRewrite(TruncOp op, OpAdaptor adaptor,
1545 ConversionPatternRewriter &rewriter)
const override {
1546 rewriter.replaceOpWithNewOp<
comb::ExtractOp>(op, adaptor.getInput(), 0,
1547 op.getType().getWidth());
1553 using OpConversionPattern::OpConversionPattern;
1556 matchAndRewrite(ZExtOp op, OpAdaptor adaptor,
1557 ConversionPatternRewriter &rewriter)
const override {
1558 auto targetWidth = op.getType().getWidth();
1559 auto inputWidth = op.getInput().getType().getWidth();
1562 rewriter, op.getLoc(),
1563 rewriter.getIntegerType(targetWidth - inputWidth), 0);
1566 op, ValueRange{zeroExt, adaptor.getInput()});
1572 using OpConversionPattern::OpConversionPattern;
1575 matchAndRewrite(SExtOp op, OpAdaptor adaptor,
1576 ConversionPatternRewriter &rewriter)
const override {
1577 auto type = typeConverter->convertType(op.getType());
1579 comb::createOrFoldSExt(op.getLoc(), adaptor.getInput(), type, rewriter);
1580 rewriter.replaceOp(op, value);
1586 using OpConversionPattern::OpConversionPattern;
1589 matchAndRewrite(SIntToRealOp op, OpAdaptor adaptor,
1590 ConversionPatternRewriter &rewriter)
const override {
1591 rewriter.replaceOpWithNewOp<arith::SIToFPOp>(
1592 op, typeConverter->convertType(op.getType()), adaptor.getInput());
1598 using OpConversionPattern::OpConversionPattern;
1601 matchAndRewrite(UIntToRealOp op, OpAdaptor adaptor,
1602 ConversionPatternRewriter &rewriter)
const override {
1603 rewriter.replaceOpWithNewOp<arith::UIToFPOp>(
1604 op, typeConverter->convertType(op.getType()), adaptor.getInput());
1610 using OpConversionPattern::OpConversionPattern;
1613 matchAndRewrite(RealToIntOp op, OpAdaptor adaptor,
1614 ConversionPatternRewriter &rewriter)
const override {
1615 rewriter.replaceOpWithNewOp<arith::FPToSIOp>(
1616 op, typeConverter->convertType(op.getType()), adaptor.getInput());
1626 using OpConversionPattern::OpConversionPattern;
1629 matchAndRewrite(hw::InstanceOp op, OpAdaptor adaptor,
1630 ConversionPatternRewriter &rewriter)
const override {
1631 SmallVector<Type> convResTypes;
1632 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
1635 rewriter.replaceOpWithNewOp<hw::InstanceOp>(
1636 op, convResTypes, op.getInstanceName(), op.getModuleName(),
1637 adaptor.getOperands(), op.getArgNames(),
1638 op.getResultNames(),
1639 rewriter.getArrayAttr({}),
nullptr);
1646 using OpConversionPattern::OpConversionPattern;
1649 matchAndRewrite(func::ReturnOp op, OpAdaptor adaptor,
1650 ConversionPatternRewriter &rewriter)
const override {
1651 rewriter.replaceOpWithNewOp<func::ReturnOp>(op, adaptor.getOperands());
1657 using OpConversionPattern::OpConversionPattern;
1660 matchAndRewrite(func::CallOp op, OpAdaptor adaptor,
1661 ConversionPatternRewriter &rewriter)
const override {
1662 SmallVector<Type> convResTypes;
1663 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
1665 rewriter.replaceOpWithNewOp<func::CallOp>(
1666 op, adaptor.getCallee(), convResTypes, adaptor.getOperands());
1671struct UnrealizedConversionCastConversion
1673 using OpConversionPattern::OpConversionPattern;
1676 matchAndRewrite(UnrealizedConversionCastOp op, OpAdaptor adaptor,
1677 ConversionPatternRewriter &rewriter)
const override {
1678 SmallVector<Type> convResTypes;
1679 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
1684 if (convResTypes == adaptor.getOperands().getTypes()) {
1685 rewriter.replaceOp(op, adaptor.getOperands());
1689 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
1690 op, convResTypes, adaptor.getOperands());
1696 using OpConversionPattern::OpConversionPattern;
1699 matchAndRewrite(ShlOp op, OpAdaptor adaptor,
1700 ConversionPatternRewriter &rewriter)
const override {
1701 Type resultType = typeConverter->convertType(op.getResult().getType());
1705 adjustIntegerWidth(rewriter, adaptor.getAmount(),
1706 resultType.getIntOrFloatBitWidth(), op->getLoc());
1707 rewriter.replaceOpWithNewOp<
comb::ShlOp>(op, resultType, adaptor.getValue(),
1714 using OpConversionPattern::OpConversionPattern;
1717 matchAndRewrite(ShrOp op, OpAdaptor adaptor,
1718 ConversionPatternRewriter &rewriter)
const override {
1719 Type resultType = typeConverter->convertType(op.getResult().getType());
1723 adjustIntegerWidth(rewriter, adaptor.getAmount(),
1724 resultType.getIntOrFloatBitWidth(), op->getLoc());
1726 op, resultType, adaptor.getValue(), amount,
false);
1732 using OpConversionPattern::OpConversionPattern;
1735 matchAndRewrite(PowUOp op, OpAdaptor adaptor,
1736 ConversionPatternRewriter &rewriter)
const override {
1737 Type resultType = typeConverter->convertType(op.getResult().getType());
1739 Location loc = op->getLoc();
1744 auto lhs = comb::ConcatOp::create(rewriter, loc, zeroVal, adaptor.getLhs());
1745 auto rhs = comb::ConcatOp::create(rewriter, loc, zeroVal, adaptor.getRhs());
1748 auto pow = mlir::math::IPowIOp::create(rewriter, loc, lhs, rhs);
1756 using OpConversionPattern::OpConversionPattern;
1759 matchAndRewrite(PowSOp op, OpAdaptor adaptor,
1760 ConversionPatternRewriter &rewriter)
const override {
1761 Type resultType = typeConverter->convertType(op.getResult().getType());
1765 rewriter.replaceOpWithNewOp<mlir::math::IPowIOp>(
1766 op, resultType, adaptor.getLhs(), adaptor.getRhs());
1772 using OpConversionPattern::OpConversionPattern;
1775 matchAndRewrite(AShrOp op, OpAdaptor adaptor,
1776 ConversionPatternRewriter &rewriter)
const override {
1777 Type resultType = typeConverter->convertType(op.getResult().getType());
1781 adjustIntegerWidth(rewriter, adaptor.getAmount(),
1782 resultType.getIntOrFloatBitWidth(), op->getLoc());
1784 op, resultType, adaptor.getValue(), amount,
false);
1790 using OpConversionPattern::OpConversionPattern;
1793 matchAndRewrite(ReadOp op, OpAdaptor adaptor,
1794 ConversionPatternRewriter &rewriter)
const override {
1795 rewriter.replaceOpWithNewOp<llhd::ProbeOp>(op, adaptor.getInput());
1800struct AssignedVariableOpConversion
1802 using OpConversionPattern::OpConversionPattern;
1805 matchAndRewrite(AssignedVariableOp op, OpAdaptor adaptor,
1806 ConversionPatternRewriter &rewriter)
const override {
1807 rewriter.replaceOpWithNewOp<hw::WireOp>(op, adaptor.getInput(),
1808 adaptor.getNameAttr());
1813template <
typename OpTy>
1816 using OpAdaptor =
typename OpTy::Adaptor;
1819 matchAndRewrite(OpTy op, OpAdaptor adaptor,
1820 ConversionPatternRewriter &rewriter)
const override {
1823 if constexpr (std::is_same_v<OpTy, ContinuousAssignOp> ||
1824 std::is_same_v<OpTy, BlockingAssignOp>) {
1826 delay = llhd::ConstantTimeOp::create(
1827 rewriter, op->getLoc(),
1828 llhd::TimeAttr::get(op->getContext(), 0U,
"ns", 0, 1));
1829 }
else if constexpr (std::is_same_v<OpTy, NonBlockingAssignOp>) {
1831 delay = llhd::ConstantTimeOp::create(
1832 rewriter, op->getLoc(),
1833 llhd::TimeAttr::get(op->getContext(), 0U,
"ns", 1, 0));
1836 delay = adaptor.getDelay();
1839 rewriter.replaceOpWithNewOp<llhd::DriveOp>(
1840 op, adaptor.getDst(), adaptor.getSrc(), delay, Value{});
1846 using OpConversionPattern::OpConversionPattern;
1849 matchAndRewrite(ConditionalOp op, OpAdaptor adaptor,
1850 ConversionPatternRewriter &rewriter)
const override {
1855 auto type = typeConverter->convertType(op.getType());
1857 auto hasNoWriteEffect = [](Region ®ion) {
1858 auto result = region.walk([](Operation *operation) {
1859 if (
auto memOp = dyn_cast<MemoryEffectOpInterface>(operation))
1860 if (!memOp.hasEffect<MemoryEffects::Write>() &&
1861 !memOp.hasEffect<MemoryEffects::Free>())
1862 return WalkResult::advance();
1864 if (operation->hasTrait<OpTrait::HasRecursiveMemoryEffects>())
1865 return WalkResult::advance();
1867 return WalkResult::interrupt();
1869 return !result.wasInterrupted();
1872 if (hasNoWriteEffect(op.getTrueRegion()) &&
1873 hasNoWriteEffect(op.getFalseRegion())) {
1874 Operation *trueTerm = op.getTrueRegion().front().getTerminator();
1875 Operation *falseTerm = op.getFalseRegion().front().getTerminator();
1877 rewriter.inlineBlockBefore(&op.getTrueRegion().front(), op);
1878 rewriter.inlineBlockBefore(&op.getFalseRegion().front(), op);
1880 Value convTrueVal = typeConverter->materializeTargetConversion(
1881 rewriter, op.getLoc(), type, trueTerm->getOperand(0));
1882 Value convFalseVal = typeConverter->materializeTargetConversion(
1883 rewriter, op.getLoc(), type, falseTerm->getOperand(0));
1885 rewriter.eraseOp(trueTerm);
1886 rewriter.eraseOp(falseTerm);
1888 rewriter.replaceOpWithNewOp<
comb::MuxOp>(op, adaptor.getCondition(),
1889 convTrueVal, convFalseVal);
1894 scf::IfOp::create(rewriter, op.getLoc(), type, adaptor.getCondition());
1895 rewriter.inlineRegionBefore(op.getTrueRegion(), ifOp.getThenRegion(),
1896 ifOp.getThenRegion().end());
1897 rewriter.inlineRegionBefore(op.getFalseRegion(), ifOp.getElseRegion(),
1898 ifOp.getElseRegion().end());
1899 rewriter.replaceOp(op, ifOp);
1905 using OpConversionPattern::OpConversionPattern;
1908 matchAndRewrite(YieldOp op, OpAdaptor adaptor,
1909 ConversionPatternRewriter &rewriter)
const override {
1910 rewriter.replaceOpWithNewOp<scf::YieldOp>(op, adaptor.getResult());
1915template <
typename SourceOp>
1918 using OpAdaptor =
typename SourceOp::Adaptor;
1921 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1922 ConversionPatternRewriter &rewriter)
const override {
1923 rewriter.modifyOpInPlace(op,
1924 [&]() { op->setOperands(adaptor.getOperands()); });
1929template <
typename MooreOpTy,
typename VerifOpTy>
1932 using OpAdaptor =
typename MooreOpTy::Adaptor;
1935 matchAndRewrite(MooreOpTy op, OpAdaptor adaptor,
1936 ConversionPatternRewriter &rewriter)
const override {
1938 op.getLabel().has_value()
1939 ? StringAttr::get(op->getContext(), op.getLabel().value())
1940 : StringAttr::
get(op->getContext());
1941 rewriter.replaceOpWithNewOp<VerifOpTy>(op, adaptor.getCond(), mlir::Value(),
1952 using OpConversionPattern::OpConversionPattern;
1955 matchAndRewrite(FormatLiteralOp op, OpAdaptor adaptor,
1956 ConversionPatternRewriter &rewriter)
const override {
1957 rewriter.replaceOpWithNewOp<sim::FormatLiteralOp>(op, adaptor.getLiteral());
1963 using OpConversionPattern::OpConversionPattern;
1966 matchAndRewrite(FormatConcatOp op, OpAdaptor adaptor,
1967 ConversionPatternRewriter &rewriter)
const override {
1968 rewriter.replaceOpWithNewOp<sim::FormatStringConcatOp>(op,
1969 adaptor.getInputs());
1975 using OpConversionPattern::OpConversionPattern;
1978 matchAndRewrite(FormatIntOp op, OpAdaptor adaptor,
1979 ConversionPatternRewriter &rewriter)
const override {
1981 switch (op.getFormat()) {
1982 case IntFormat::Decimal:
1983 rewriter.replaceOpWithNewOp<sim::FormatDecOp>(op, adaptor.getValue());
1985 case IntFormat::Binary:
1986 rewriter.replaceOpWithNewOp<sim::FormatBinOp>(op, adaptor.getValue());
1988 case IntFormat::Octal:
1989 rewriter.replaceOpWithNewOp<sim::FormatOctOp>(op, adaptor.getValue());
1991 case IntFormat::HexLower:
1992 case IntFormat::HexUpper:
1993 rewriter.replaceOpWithNewOp<sim::FormatHexOp>(op, adaptor.getValue());
1996 return rewriter.notifyMatchFailure(op,
"unsupported int format");
2002 using OpConversionPattern::OpConversionPattern;
2005 matchAndRewrite(DisplayBIOp op, OpAdaptor adaptor,
2006 ConversionPatternRewriter &rewriter)
const override {
2007 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(
2008 op, adaptor.getMessage());
2020static LogicalResult
convert(StopBIOp op, StopBIOp::Adaptor adaptor,
2021 ConversionPatternRewriter &rewriter) {
2022 rewriter.replaceOpWithNewOp<sim::PauseOp>(op,
false);
2027static LogicalResult
convert(FinishBIOp op, FinishBIOp::Adaptor adaptor,
2028 ConversionPatternRewriter &rewriter) {
2029 rewriter.replaceOpWithNewOp<sim::TerminateOp>(op, op.getExitCode() == 0,
2035static LogicalResult
convert(SeverityBIOp op, SeverityBIOp::Adaptor adaptor,
2036 ConversionPatternRewriter &rewriter) {
2038 std::string severityString;
2040 switch (op.getSeverity()) {
2041 case (Severity::Fatal):
2042 severityString =
"Fatal: ";
2044 case (Severity::Error):
2045 severityString =
"Error: ";
2047 case (Severity::Warning):
2048 severityString =
"Warning: ";
2055 sim::FormatLiteralOp::create(rewriter, op.getLoc(), severityString);
2056 auto message = sim::FormatStringConcatOp::create(
2057 rewriter, op.getLoc(), ValueRange{prefix, adaptor.getMessage()});
2058 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(op, message);
2064 FinishMessageBIOp::Adaptor adaptor,
2065 ConversionPatternRewriter &rewriter) {
2067 rewriter.eraseOp(op);
2076 const TypeConverter &converter) {
2077 target.addIllegalDialect<MooreDialect>();
2078 target.addLegalDialect<comb::CombDialect>();
2079 target.addLegalDialect<hw::HWDialect>();
2080 target.addLegalDialect<seq::SeqDialect>();
2081 target.addLegalDialect<llhd::LLHDDialect>();
2082 target.addLegalDialect<ltl::LTLDialect>();
2083 target.addLegalDialect<mlir::BuiltinDialect>();
2084 target.addLegalDialect<mlir::math::MathDialect>();
2085 target.addLegalDialect<sim::SimDialect>();
2086 target.addLegalDialect<mlir::LLVM::LLVMDialect>();
2087 target.addLegalDialect<verif::VerifDialect>();
2088 target.addLegalDialect<arith::ArithDialect>();
2090 target.addLegalOp<debug::ScopeOp>();
2092 target.addDynamicallyLegalOp<scf::YieldOp, func::CallOp, func::ReturnOp,
2093 UnrealizedConversionCastOp, hw::OutputOp,
2094 hw::InstanceOp, debug::ArrayOp, debug::StructOp,
2096 [&](Operation *op) {
return converter.isLegal(op); });
2098 target.addDynamicallyLegalOp<scf::IfOp, scf::ForOp, scf::ExecuteRegionOp,
2099 scf::WhileOp, scf::ForallOp>([&](Operation *op) {
2100 return converter.isLegal(op) && !op->getParentOfType<llhd::ProcessOp>();
2103 target.addDynamicallyLegalOp<func::FuncOp>([&](func::FuncOp op) {
2104 return converter.isSignatureLegal(op.getFunctionType());
2108 return converter.isSignatureLegal(op.getModuleType().getFuncType()) &&
2109 converter.isLegal(&op.getBody());
2114 typeConverter.addConversion([&](IntType type) {
2115 return IntegerType::get(type.getContext(), type.getWidth());
2118 typeConverter.addConversion([&](RealType type) -> mlir::Type {
2119 MLIRContext *ctx = type.getContext();
2120 switch (type.getWidth()) {
2121 case moore::RealWidth::f32:
2122 return mlir::Float32Type::get(ctx);
2123 case moore::RealWidth::f64:
2124 return mlir::Float64Type::get(ctx);
2128 typeConverter.addConversion(
2129 [&](TimeType type) {
return llhd::TimeType::get(type.getContext()); });
2131 typeConverter.addConversion([&](FormatStringType type) {
2132 return sim::FormatStringType::get(type.getContext());
2135 typeConverter.addConversion([&](ArrayType type) -> std::optional<Type> {
2136 if (
auto elementType = typeConverter.convertType(type.getElementType()))
2137 return hw::ArrayType::get(
elementType, type.getSize());
2144 typeConverter.addConversion(
2145 [&](UnpackedArrayType type) -> std::optional<Type> {
2146 if (
auto elementType = typeConverter.convertType(type.getElementType()))
2147 return hw::ArrayType::get(
elementType, type.getSize());
2151 typeConverter.addConversion([&](StructType type) -> std::optional<Type> {
2152 SmallVector<hw::StructType::FieldInfo> fields;
2153 for (
auto field : type.getMembers()) {
2154 hw::StructType::FieldInfo info;
2155 info.type = typeConverter.convertType(field.type);
2158 info.name = field.name;
2159 fields.push_back(info);
2161 return hw::StructType::get(type.getContext(), fields);
2169 typeConverter.addConversion(
2170 [&](UnpackedStructType type) -> std::optional<Type> {
2171 SmallVector<hw::StructType::FieldInfo> fields;
2172 for (
auto field : type.getMembers()) {
2173 hw::StructType::FieldInfo info;
2174 info.type = typeConverter.convertType(field.type);
2177 info.name = field.name;
2178 fields.push_back(info);
2180 return hw::StructType::get(type.getContext(), fields);
2184 typeConverter.addConversion([&](ChandleType type) -> std::optional<Type> {
2185 return LLVM::LLVMPointerType::get(type.getContext());
2189 typeConverter.addConversion(
2190 [](LLVM::LLVMPointerType t) -> std::optional<Type> {
return t; });
2193 typeConverter.addConversion([&](ClassHandleType type) -> std::optional<Type> {
2194 return LLVM::LLVMPointerType::get(type.getContext());
2197 typeConverter.addConversion([&](RefType type) -> std::optional<Type> {
2198 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
2199 return llhd::RefType::get(innerType);
2204 typeConverter.addConversion([](IntegerType type) {
return type; });
2205 typeConverter.addConversion([](FloatType type) {
return type; });
2206 typeConverter.addConversion([](llhd::TimeType type) {
return type; });
2207 typeConverter.addConversion([](debug::ArrayType type) {
return type; });
2208 typeConverter.addConversion([](debug::ScopeType type) {
return type; });
2209 typeConverter.addConversion([](debug::StructType type) {
return type; });
2211 typeConverter.addConversion([&](llhd::RefType type) -> std::optional<Type> {
2212 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
2213 return llhd::RefType::get(innerType);
2217 typeConverter.addConversion([&](hw::ArrayType type) -> std::optional<Type> {
2218 if (
auto elementType = typeConverter.convertType(type.getElementType()))
2219 return hw::ArrayType::get(
elementType, type.getNumElements());
2223 typeConverter.addConversion([&](hw::StructType type) -> std::optional<Type> {
2224 SmallVector<hw::StructType::FieldInfo> fields;
2225 for (
auto field : type.getElements()) {
2226 hw::StructType::FieldInfo info;
2227 info.type = typeConverter.convertType(field.type);
2230 info.name = field.name;
2231 fields.push_back(info);
2233 return hw::StructType::get(type.getContext(), fields);
2236 typeConverter.addTargetMaterialization(
2237 [&](mlir::OpBuilder &builder, mlir::Type resultType,
2238 mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
2239 if (inputs.size() != 1 || !inputs[0])
2241 return UnrealizedConversionCastOp::create(builder, loc, resultType,
2246 typeConverter.addSourceMaterialization(
2247 [&](mlir::OpBuilder &builder, mlir::Type resultType,
2248 mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
2249 if (inputs.size() != 1)
2251 return UnrealizedConversionCastOp::create(builder, loc, resultType,
2258 TypeConverter &typeConverter,
2259 ClassTypeCache &classCache) {
2265 patterns.add<ClassPropertyRefOpConversion>(typeConverter,
2266 patterns.getContext(), classCache);
2270 ClassUpcastOpConversion,
2272 VariableOpConversion,
2276 ConversionOpConversion,
2277 BitcastConversion<PackedToSBVOp>,
2278 BitcastConversion<SBVToPackedOp>,
2279 BitcastConversion<LogicToIntOp>,
2280 BitcastConversion<IntToLogicOp>,
2281 BitcastConversion<ToBuiltinBoolOp>,
2285 SIntToRealOpConversion,
2286 UIntToRealOpConversion,
2287 RealToIntOpConversion,
2293 ReplicateOpConversion,
2295 ExtractOpConversion,
2296 DynExtractOpConversion,
2297 DynExtractRefOpConversion,
2299 StructExtractOpConversion,
2300 StructExtractRefOpConversion,
2301 ExtractRefOpConversion,
2302 StructCreateOpConversion,
2303 ConditionalOpConversion,
2304 ArrayCreateOpConversion,
2307 ConstantStringOpConv,
2310 ReduceAndOpConversion,
2311 ReduceOrOpConversion,
2312 ReduceXorOpConversion,
2313 BoolCastOpConversion,
2318 BinaryOpConversion<AddOp, comb::AddOp>,
2319 BinaryOpConversion<SubOp, comb::SubOp>,
2320 BinaryOpConversion<MulOp, comb::MulOp>,
2321 BinaryOpConversion<DivUOp, comb::DivUOp>,
2322 BinaryOpConversion<DivSOp, comb::DivSOp>,
2323 BinaryOpConversion<ModUOp, comb::ModUOp>,
2324 BinaryOpConversion<ModSOp, comb::ModSOp>,
2325 BinaryOpConversion<AndOp, comb::AndOp>,
2326 BinaryOpConversion<OrOp, comb::OrOp>,
2327 BinaryOpConversion<XorOp, comb::XorOp>,
2330 PowUOpConversion, PowSOpConversion,
2333 ICmpOpConversion<UltOp, ICmpPredicate::ult>,
2334 ICmpOpConversion<SltOp, ICmpPredicate::slt>,
2335 ICmpOpConversion<UleOp, ICmpPredicate::ule>,
2336 ICmpOpConversion<SleOp, ICmpPredicate::sle>,
2337 ICmpOpConversion<UgtOp, ICmpPredicate::ugt>,
2338 ICmpOpConversion<SgtOp, ICmpPredicate::sgt>,
2339 ICmpOpConversion<UgeOp, ICmpPredicate::uge>,
2340 ICmpOpConversion<SgeOp, ICmpPredicate::sge>,
2341 ICmpOpConversion<EqOp, ICmpPredicate::eq>,
2342 ICmpOpConversion<NeOp, ICmpPredicate::ne>,
2343 ICmpOpConversion<CaseEqOp, ICmpPredicate::ceq>,
2344 ICmpOpConversion<CaseNeOp, ICmpPredicate::cne>,
2345 ICmpOpConversion<WildcardEqOp, ICmpPredicate::weq>,
2346 ICmpOpConversion<WildcardNeOp, ICmpPredicate::wne>,
2347 CaseXZEqOpConversion<CaseZEqOp, true>,
2348 CaseXZEqOpConversion<CaseXZEqOp, false>,
2351 SVModuleOpConversion,
2352 InstanceOpConversion,
2353 ProcedureOpConversion,
2354 WaitEventOpConversion,
2362 AssignOpConversion<ContinuousAssignOp>,
2363 AssignOpConversion<DelayedContinuousAssignOp>,
2364 AssignOpConversion<BlockingAssignOp>,
2365 AssignOpConversion<NonBlockingAssignOp>,
2366 AssignOpConversion<DelayedNonBlockingAssignOp>,
2367 AssignedVariableOpConversion,
2370 HWInstanceOpConversion,
2373 UnrealizedConversionCastConversion,
2374 InPlaceOpConversion<debug::ArrayOp>,
2375 InPlaceOpConversion<debug::StructOp>,
2376 InPlaceOpConversion<debug::VariableOp>,
2379 AssertLikeOpConversion<AssertOp, verif::AssertOp>,
2380 AssertLikeOpConversion<AssumeOp, verif::AssumeOp>,
2381 AssertLikeOpConversion<CoverOp, verif::CoverOp>,
2384 FormatLiteralOpConversion,
2385 FormatConcatOpConversion,
2386 FormatIntOpConversion,
2387 DisplayBIOpConversion
2388 >(typeConverter,
patterns.getContext());
2401 mlir::populateAnyFunctionOpInterfaceTypeConversionPattern(
patterns,
2403 hw::populateHWModuleLikeTypeConversionPattern(
2404 hw::HWModuleOp::getOperationName(),
patterns, typeConverter);
2405 populateSCFToControlFlowConversionPatterns(
patterns);
2414struct MooreToCorePass
2415 :
public circt::impl::ConvertMooreToCoreBase<MooreToCorePass> {
2416 void runOnOperation()
override;
2422 return std::make_unique<MooreToCorePass>();
2426void MooreToCorePass::runOnOperation() {
2427 MLIRContext &
context = getContext();
2428 ModuleOp
module = getOperation();
2429 ClassTypeCache classCache;
2431 IRRewriter rewriter(module);
2432 (void)mlir::eraseUnreachableBlocks(rewriter, module->getRegions());
2434 TypeConverter typeConverter;
2437 ConversionTarget target(
context);
2442 mlir::cf::populateCFStructuralTypeConversionsAndLegality(typeConverter,
2445 if (failed(applyFullConversion(module, target, std::move(
patterns))))
2446 signalPassFailure();
assert(baseType &&"element must be base type")
static SmallVector< T > concat(const SmallVectorImpl< T > &a, const SmallVectorImpl< T > &b)
Returns a new vector containing the concatenation of vectors a and b.
static 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.