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 {
56 LLVM::GlobalOp global;
59 struct ClassStructInfo {
60 LLVM::LLVMStructType classBody;
61 LLVM::LLVMStructType headerTy;
62 TypeInfoInfo typeInfo;
64 unsigned headerFieldIndex = 0;
65 unsigned typeInfoFieldIndex = 0;
66 unsigned vtableFieldIndex = 1;
69 DenseMap<StringRef, SmallVector<unsigned, 2>> propertyPath;
73 void setFieldPath(StringRef propertyName, ArrayRef<unsigned> path) {
74 this->propertyPath[propertyName] =
75 SmallVector<unsigned, 2>(path.begin(), path.end());
79 std::optional<ArrayRef<unsigned>>
80 getFieldPath(StringRef propertySym)
const {
81 if (
auto prop = this->propertyPath.find(propertySym);
82 prop != this->propertyPath.end())
83 return ArrayRef<unsigned>(prop->second);
90 void setClassInfo(SymbolRefAttr classSym,
const ClassStructInfo &
info) {
91 auto &dst = classToStructMap[classSym];
96 std::optional<ClassStructInfo> getStructInfo(SymbolRefAttr classSym)
const {
97 if (
auto it = classToStructMap.find(classSym); it != classToStructMap.end())
102 std::optional<TypeInfoInfo> getTypeInfo(SymbolRefAttr classSym)
const {
103 if (
auto it = classToTypeInfoMap.find(classSym);
104 it != classToTypeInfoMap.end())
109 void setTypeInfo(SymbolRefAttr classSym,
const TypeInfoInfo &
info) {
110 classToTypeInfoMap[classSym] =
info;
117 DenseMap<Attribute, ClassStructInfo> classToStructMap;
118 DenseMap<Attribute, TypeInfoInfo> classToTypeInfoMap;
123struct FunctionCache {
124 FunctionCache(SymbolTable &symbolTable) : symbolTable(symbolTable) {}
130 func::FuncOp getOrCreate(OpBuilder &builder, StringRef name,
131 function_ref<func::FuncOp()> createFn) {
132 auto &slot = map[name];
135 if (
auto fn = symbolTable.lookup<func::FuncOp>(name))
137 auto mod = cast<ModuleOp>(symbolTable.getOp());
138 OpBuilder::InsertionGuard g(builder);
139 builder.setInsertionPointToStart(mod.getBody());
141 symbolTable.insert(slot);
147 func::FuncOp getOrCreate(OpBuilder &builder, StringRef name,
148 TypeRange argTypes, TypeRange resultTypes) {
149 return getOrCreate(builder, name, [&] {
150 auto mod = cast<ModuleOp>(symbolTable.getOp());
151 auto fnTy = builder.getFunctionType(argTypes, resultTypes);
152 auto fn = func::FuncOp::create(builder, mod.getLoc(), name, fnTy);
159 SymbolTable &symbolTable;
160 llvm::StringMap<func::FuncOp> map;
165static LLVM::LLVMStructType getOrCreateOpaqueStruct(MLIRContext *ctx,
166 SymbolRefAttr className) {
167 return LLVM::LLVMStructType::getIdentified(ctx, className.getRootReference());
171static LLVM::LLVMStructType getClassObjectHeaderType(MLIRContext *ctx) {
172 return LLVM::LLVMStructType::getLiteral(
173 ctx, SmallVector<Type>{LLVM::LLVMPointerType::get(ctx),
174 LLVM::LLVMPointerType::get(ctx)});
177static std::string getTypeInfoName(SymbolRefAttr className) {
178 return className.getRootReference().str() +
"::typeinfo";
181static FailureOr<ClassTypeCache::TypeInfoInfo>
182getOrCreateTypeInfo(ModuleOp mod, SymbolRefAttr classSym,
183 ClassTypeCache &cache) {
184 if (
auto info = cache.getTypeInfo(classSym))
187 MLIRContext *ctx = mod.getContext();
188 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
189 auto typeInfoTy = LLVM::LLVMStructType::getLiteral(ctx, {ptrTy});
191 auto globalName = getTypeInfoName(classSym);
192 auto global = mod.lookupSymbol<LLVM::GlobalOp>(globalName);
194 OpBuilder builder = OpBuilder::atBlockBegin(mod.getBody());
195 global = LLVM::GlobalOp::create(
196 builder, mod.getLoc(), typeInfoTy,
197 true, LLVM::Linkage::Internal, globalName, Attribute());
200 global.getInitializerRegion().push_back(block);
201 builder.setInsertionPointToStart(block);
203 if (
auto *classOp = mod.lookupSymbol(classSym)) {
204 auto classDecl = dyn_cast<ClassDeclOp>(classOp);
205 if (classDecl && classDecl.getBaseAttr()) {
207 getOrCreateTypeInfo(mod, classDecl.getBaseAttr(), cache);
208 if (failed(baseInfo))
211 LLVM::AddressOfOp::create(builder, mod.getLoc(), baseInfo->global);
212 auto undef = LLVM::UndefOp::create(builder, mod.getLoc(), typeInfoTy)
214 auto init = LLVM::InsertValueOp::create(builder, mod.getLoc(), undef,
215 baseAddr.getResult(),
216 ArrayRef<int64_t>{0});
217 LLVM::ReturnOp::create(builder, mod.getLoc(), init);
218 ClassTypeCache::TypeInfoInfo
info{global};
219 cache.setTypeInfo(classSym, info);
225 LLVM::UndefOp::create(builder, mod.getLoc(), typeInfoTy).getResult();
227 LLVM::ZeroOp::create(builder, mod.getLoc(), ptrTy).getResult();
228 auto init = LLVM::InsertValueOp::create(builder, mod.getLoc(), undef,
229 nullPtr, ArrayRef<int64_t>{0});
230 LLVM::ReturnOp::create(builder, mod.getLoc(), init);
233 ClassTypeCache::TypeInfoInfo
info{global};
234 cache.setTypeInfo(classSym, info);
237static LogicalResult resolveClassStructBody(ClassDeclOp op,
238 TypeConverter
const &typeConverter,
239 ClassTypeCache &cache) {
241 auto classSym = SymbolRefAttr::get(op.getSymNameAttr());
242 auto structInfo = cache.getStructInfo(classSym);
247 if (failed(getOrCreateTypeInfo(op->getParentOfType<ModuleOp>(), classSym,
249 return op.emitOpError() <<
"Failed to create RTTI for class";
252 ClassTypeCache::ClassStructInfo structBody;
253 SmallVector<Type> structBodyMembers;
254 structBody.headerTy = getClassObjectHeaderType(op.getContext());
255 structBody.typeInfo = *cache.getTypeInfo(classSym);
256 structBodyMembers.push_back(structBody.headerTy);
259 unsigned derivedStartIdx = 1;
261 if (
auto baseClass = op.getBaseAttr()) {
263 ModuleOp mod = op->getParentOfType<ModuleOp>();
264 auto *opSym = mod.lookupSymbol(baseClass);
265 auto classDeclOp = cast<ClassDeclOp>(opSym);
267 if (failed(resolveClassStructBody(classDeclOp, typeConverter, cache)))
271 auto baseClassStruct = cache.getStructInfo(baseClass);
272 structBodyMembers.push_back(baseClassStruct->classBody);
277 for (
auto &kv : baseClassStruct->propertyPath) {
278 SmallVector<unsigned, 2> path;
280 path.append(kv.second.begin(), kv.second.end());
281 structBody.setFieldPath(kv.first, path);
286 unsigned iterator = derivedStartIdx;
287 auto &block = op.getBody().front();
288 for (Operation &child : block) {
289 if (
auto prop = dyn_cast<ClassPropertyDeclOp>(child)) {
290 Type mooreTy = prop.getPropertyType();
291 Type llvmTy = typeConverter.convertType(mooreTy);
293 return prop.emitOpError()
294 <<
"failed to convert property type " << mooreTy;
296 structBodyMembers.push_back(llvmTy);
299 SmallVector<unsigned, 2> path{iterator};
300 structBody.setFieldPath(prop.getSymName(), path);
306 auto llvmStructTy = getOrCreateOpaqueStruct(op.getContext(), classSym);
308 if (!structBodyMembers.empty() &&
309 failed(llvmStructTy.setBody(structBodyMembers,
false)))
310 return op.emitOpError() <<
"Failed to set LLVM Struct body";
312 structBody.classBody = llvmStructTy;
313 cache.setClassInfo(classSym, structBody);
319static LogicalResult resolveClassStructBody(ModuleOp mod, SymbolRefAttr op,
320 TypeConverter
const &typeConverter,
321 ClassTypeCache &cache) {
322 auto classDeclOp = cast<ClassDeclOp>(*mod.lookupSymbol(op));
323 return resolveClassStructBody(classDeclOp, typeConverter, cache);
330static Value adjustIntegerWidth(OpBuilder &builder, Value value,
331 uint32_t targetWidth, Location loc) {
332 uint32_t intWidth = value.getType().getIntOrFloatBitWidth();
333 if (intWidth == targetWidth)
336 if (intWidth < targetWidth) {
338 builder, loc, builder.getIntegerType(targetWidth - intWidth), 0);
339 return comb::ConcatOp::create(builder, loc, ValueRange{zeroExt, value});
343 intWidth - targetWidth);
345 builder, loc, builder.getIntegerType(intWidth - targetWidth), 0);
346 Value isZero = comb::ICmpOp::create(builder, loc, comb::ICmpPredicate::eq, hi,
350 builder.getIntegerType(targetWidth), -1);
351 return comb::MuxOp::create(builder, loc, isZero, lo, max,
false);
355static FailureOr<hw::ModulePortInfo>
356getModulePortInfo(
const TypeConverter &typeConverter, SVModuleOp op) {
358 size_t resultNum = 0;
359 auto moduleTy = op.getModuleType();
360 SmallVector<hw::PortInfo> ports;
361 ports.reserve(moduleTy.getNumPorts());
363 for (
auto port : moduleTy.getPorts()) {
364 Type portTy = typeConverter.convertType(port.type);
366 return op.emitOpError(
"port '")
367 << port.name <<
"' has unsupported type " << port.type
368 <<
" that cannot be converted to hardware type";
370 if (port.dir == hw::ModulePort::Direction::Output) {
372 hw::PortInfo({{port.name, portTy, port.dir}, resultNum++, {}}));
380 hw::PortInfo({{port.name, portTy, port.dir}, inputNum++, {}}));
386struct DpiArrayCastInfo {
389 bool isPacked =
false;
393static std::optional<DpiArrayCastInfo> getDpiArrayCastInfo(Type type) {
394 DpiArrayCastInfo
info;
395 if (
auto refType = dyn_cast<RefType>(type)) {
397 type = refType.getNestedType();
400 if (
auto arrayType = dyn_cast<ArrayType>(type)) {
401 info.isPacked =
true;
402 info.elementType = arrayType.getElementType();
405 if (
auto arrayType = dyn_cast<OpenArrayType>(type)) {
407 info.isPacked =
true;
408 info.elementType = arrayType.getElementType();
411 if (
auto arrayType = dyn_cast<UnpackedArrayType>(type)) {
412 info.elementType = arrayType.getElementType();
415 if (
auto arrayType = dyn_cast<OpenUnpackedArrayType>(type)) {
417 info.elementType = arrayType.getElementType();
423static bool hasOpenArrayBoundaryType(Type type) {
424 if (isa<OpenArrayType, OpenUnpackedArrayType>(type))
426 if (
auto refType = dyn_cast<RefType>(type))
427 return isa<OpenArrayType, OpenUnpackedArrayType>(refType.getNestedType());
431static bool isSupportedDpiOpenArrayCast(Type source, Type target) {
432 auto sourceInfo = getDpiArrayCastInfo(source);
433 auto targetInfo = getDpiArrayCastInfo(target);
434 if (!sourceInfo || !targetInfo)
439 return sourceInfo->isRef == targetInfo->isRef &&
440 sourceInfo->isPacked == targetInfo->isPacked &&
441 sourceInfo->elementType == targetInfo->elementType &&
442 (targetInfo->isOpen && !sourceInfo->isOpen);
450 using OpConversionPattern::OpConversionPattern;
453 matchAndRewrite(SVModuleOp op, OpAdaptor adaptor,
454 ConversionPatternRewriter &rewriter)
const override {
455 rewriter.setInsertionPoint(op);
458 auto portInfo = getModulePortInfo(*typeConverter, op);
459 if (failed(portInfo))
462 auto hwModuleOp = hw::HWModuleOp::create(rewriter, op.getLoc(),
463 op.getSymNameAttr(), *portInfo);
466 SymbolTable::setSymbolVisibility(hwModuleOp,
467 SymbolTable::getSymbolVisibility(op));
468 rewriter.eraseBlock(hwModuleOp.getBodyBlock());
470 rewriter.convertRegionTypes(&op.getBodyRegion(), *typeConverter)))
472 rewriter.inlineRegionBefore(op.getBodyRegion(), hwModuleOp.getBodyRegion(),
473 hwModuleOp.getBodyRegion().end());
476 rewriter.eraseOp(op);
482 using OpConversionPattern::OpConversionPattern;
485 matchAndRewrite(OutputOp op, OpAdaptor adaptor,
486 ConversionPatternRewriter &rewriter)
const override {
487 rewriter.replaceOpWithNewOp<hw::OutputOp>(op, adaptor.getOperands());
493 using OpConversionPattern::OpConversionPattern;
496 matchAndRewrite(InstanceOp op, OpAdaptor adaptor,
497 ConversionPatternRewriter &rewriter)
const override {
498 auto instName = op.getInstanceNameAttr();
499 auto moduleName = op.getModuleNameAttr();
502 rewriter.setInsertionPoint(op);
503 auto instOp = hw::InstanceOp::create(
504 rewriter, op.getLoc(), op.getResultTypes(), instName, moduleName,
505 op.getInputs(), op.getInputNamesAttr(), op.getOutputNamesAttr(),
506 rewriter.getArrayAttr({}),
nullptr,
510 op.replaceAllUsesWith(instOp.getResults());
511 rewriter.eraseOp(op);
516static void getValuesToObserve(Region *region,
517 function_ref<
void(Value)> setInsertionPoint,
518 const TypeConverter *typeConverter,
519 ConversionPatternRewriter &rewriter,
520 SmallVector<Value> &observeValues) {
521 SmallDenseSet<Value> alreadyObserved;
522 Location loc = region->getLoc();
524 auto probeIfSignal = [&](Value value) -> Value {
525 if (!isa<llhd::RefType>(value.getType()))
527 return llhd::ProbeOp::create(rewriter, loc, value);
530 region->getParentOp()->walk<WalkOrder::PreOrder, ForwardDominanceIterator<>>(
531 [&](Operation *operation) {
532 for (
auto value : operation->getOperands()) {
533 if (isa<BlockArgument>(value))
534 value = rewriter.getRemappedValue(value);
536 if (region->isAncestor(value.getParentRegion()))
538 if (
auto *defOp = value.getDefiningOp();
539 defOp && defOp->hasTrait<OpTrait::ConstantLike>())
541 if (!alreadyObserved.insert(value).second)
544 OpBuilder::InsertionGuard g(rewriter);
545 if (
auto remapped = rewriter.getRemappedValue(value)) {
546 setInsertionPoint(remapped);
547 observeValues.push_back(probeIfSignal(remapped));
549 setInsertionPoint(value);
550 auto type = typeConverter->convertType(value.getType());
551 auto converted = typeConverter->materializeTargetConversion(
552 rewriter, loc, type, value);
553 observeValues.push_back(probeIfSignal(converted));
560 using OpConversionPattern::OpConversionPattern;
563 matchAndRewrite(ProcedureOp op, OpAdaptor adaptor,
564 ConversionPatternRewriter &rewriter)
const override {
566 SmallVector<Value> observedValues;
567 if (op.getKind() == ProcedureKind::AlwaysComb ||
568 op.getKind() == ProcedureKind::AlwaysLatch) {
569 auto setInsertionPoint = [&](Value value) {
570 rewriter.setInsertionPoint(op);
572 getValuesToObserve(&op.getBody(), setInsertionPoint, typeConverter,
573 rewriter, observedValues);
576 auto loc = op.getLoc();
577 if (failed(rewriter.convertRegionTypes(&op.getBody(), *typeConverter)))
582 if (op.getKind() == ProcedureKind::Initial ||
583 op.getKind() == ProcedureKind::Final) {
585 if (op.getKind() == ProcedureKind::Initial)
586 newOp = llhd::ProcessOp::create(rewriter, loc, TypeRange{});
588 newOp = llhd::FinalOp::create(rewriter, loc);
589 auto &body = newOp->getRegion(0);
590 rewriter.inlineRegionBefore(op.getBody(), body, body.end());
592 llvm::make_early_inc_range(body.getOps<ReturnOp>())) {
593 rewriter.setInsertionPoint(returnOp);
594 rewriter.replaceOpWithNewOp<llhd::HaltOp>(returnOp, ValueRange{});
596 rewriter.eraseOp(op);
601 auto newOp = llhd::ProcessOp::create(rewriter, loc, TypeRange{});
606 rewriter.createBlock(&newOp.getBody());
607 auto *block = &op.getBody().front();
608 cf::BranchOp::create(rewriter, loc, block);
609 rewriter.inlineRegionBefore(op.getBody(), newOp.getBody(),
610 newOp.getBody().end());
618 if (op.getKind() == ProcedureKind::AlwaysComb ||
619 op.getKind() == ProcedureKind::AlwaysLatch) {
620 Block *waitBlock = rewriter.createBlock(&newOp.getBody());
621 llhd::WaitOp::create(rewriter, loc, ValueRange{}, Value(), observedValues,
622 ValueRange{}, block);
629 for (
auto returnOp :
llvm::make_early_inc_range(newOp.getOps<ReturnOp>())) {
630 rewriter.setInsertionPoint(returnOp);
631 cf::BranchOp::create(rewriter, loc, block);
632 rewriter.eraseOp(returnOp);
635 rewriter.eraseOp(op);
645 using OpConversionPattern::OpConversionPattern;
648 matchAndRewrite(CoroutineOp op, OpAdaptor adaptor,
649 ConversionPatternRewriter &rewriter)
const override {
650 auto funcType = op.getFunctionType();
651 TypeConverter::SignatureConversion sigConversion(funcType.getNumInputs());
652 for (
auto [i, type] :
llvm::enumerate(funcType.getInputs())) {
653 auto converted = typeConverter->convertType(type);
656 sigConversion.addInputs(i, converted);
658 SmallVector<Type> resultTypes;
659 if (failed(typeConverter->convertTypes(funcType.getResults(), resultTypes)))
662 auto newFuncType = FunctionType::get(
663 rewriter.getContext(), sigConversion.getConvertedTypes(), resultTypes);
664 auto newOp = llhd::CoroutineOp::create(rewriter, op.getLoc(),
665 op.getSymName(), newFuncType);
666 newOp.setSymVisibilityAttr(op.getSymVisibilityAttr());
667 if (
auto dpiExport = op->getAttr(
"circt.dpi.export"))
668 newOp->setAttr(
"circt.dpi.export", dpiExport);
669 rewriter.inlineRegionBefore(op.getBody(), newOp.getBody(),
670 newOp.getBody().end());
671 if (failed(rewriter.convertRegionTypes(&newOp.getBody(), *typeConverter,
677 llvm::make_early_inc_range(newOp.getBody().getOps<ReturnOp>())) {
678 rewriter.setInsertionPoint(returnOp);
679 rewriter.replaceOpWithNewOp<llhd::ReturnOp>(returnOp, ValueRange{});
682 rewriter.eraseOp(op);
688 using OpConversionPattern::OpConversionPattern;
691 matchAndRewrite(CallCoroutineOp op, OpAdaptor adaptor,
692 ConversionPatternRewriter &rewriter)
const override {
693 SmallVector<Type> convResTypes;
694 if (failed(typeConverter->convertTypes(op.getResultTypes(), convResTypes)))
696 rewriter.replaceOpWithNewOp<llhd::CallCoroutineOp>(
697 op, convResTypes, adaptor.getCallee(), adaptor.getOperands());
703 using OpConversionPattern::OpConversionPattern;
706 matchAndRewrite(WaitEventOp op, OpAdaptor adaptor,
707 ConversionPatternRewriter &rewriter)
const override {
741 rewriter.splitBlock(op->getBlock(), ++Block::iterator(op));
747 if (op.getBody().front().empty()) {
750 rewriter.replaceOpWithNewOp<llhd::HaltOp>(op, ValueRange{});
754 auto *waitBlock = rewriter.createBlock(resumeBlock);
755 auto *checkBlock = rewriter.createBlock(resumeBlock);
757 auto loc = op.getLoc();
758 rewriter.setInsertionPoint(op);
759 cf::BranchOp::create(rewriter, loc, waitBlock);
769 SmallVector<Value> valuesBefore;
770 rewriter.setInsertionPointToEnd(waitBlock);
771 auto clonedOp = cast<WaitEventOp>(rewriter.clone(*op));
772 bool allDetectsAreAnyChange =
true;
774 llvm::make_early_inc_range(clonedOp.getOps<DetectEventOp>())) {
775 if (detectOp.getEdge() != Edge::AnyChange || detectOp.getCondition())
776 allDetectsAreAnyChange =
false;
777 valuesBefore.push_back(detectOp.getInput());
778 rewriter.eraseOp(detectOp);
784 SmallVector<Value> observeValues;
785 auto setInsertionPointAfterDef = [&](Value value) {
786 if (
auto *op = value.getDefiningOp())
787 rewriter.setInsertionPointAfter(op);
788 if (
auto arg = dyn_cast<BlockArgument>(value))
789 rewriter.setInsertionPointToStart(value.getParentBlock());
792 getValuesToObserve(&clonedOp.getBody(), setInsertionPointAfterDef,
793 typeConverter, rewriter, observeValues);
798 auto waitOp = llhd::WaitOp::create(rewriter, loc, ValueRange{}, Value(),
799 observeValues, ValueRange{}, checkBlock);
800 rewriter.inlineBlockBefore(&clonedOp.getBody().front(), waitOp);
801 rewriter.eraseOp(clonedOp);
805 SmallVector<DetectEventOp> detectOps(op.getBody().getOps<DetectEventOp>());
806 rewriter.inlineBlockBefore(&op.getBody().front(), checkBlock,
808 rewriter.eraseOp(op);
812 auto computeTrigger = [&](Value before, Value after, Edge edge) -> Value {
813 assert(before.getType() == after.getType() &&
814 "mismatched types after clone op");
815 auto beforeType = cast<IntType>(before.getType());
819 if (beforeType.getWidth() != 1 && edge != Edge::AnyChange) {
820 constexpr int LSB = 0;
822 IntType::get(rewriter.getContext(), 1, beforeType.getDomain());
824 moore::ExtractOp::create(rewriter, loc, beforeType, before, LSB);
825 after = moore::ExtractOp::create(rewriter, loc, beforeType, after, LSB);
828 auto intType = rewriter.getIntegerType(beforeType.getWidth());
829 before = typeConverter->materializeTargetConversion(rewriter, loc,
831 after = typeConverter->materializeTargetConversion(rewriter, loc, intType,
834 if (edge == Edge::AnyChange)
835 return comb::ICmpOp::create(rewriter, loc, ICmpPredicate::ne, before,
838 SmallVector<Value> disjuncts;
841 if (edge == Edge::PosEdge || edge == Edge::BothEdges) {
843 comb::XorOp::create(rewriter, loc, before, trueVal,
true);
845 comb::AndOp::create(rewriter, loc, notOldVal, after,
true);
846 disjuncts.push_back(posedge);
849 if (edge == Edge::NegEdge || edge == Edge::BothEdges) {
851 comb::XorOp::create(rewriter, loc, after, trueVal,
true);
853 comb::AndOp::create(rewriter, loc, before, notCurrVal,
true);
854 disjuncts.push_back(posedge);
857 return rewriter.createOrFold<
comb::OrOp>(loc, disjuncts,
true);
864 SmallVector<Value> triggers;
865 for (
auto [detectOp, before] :
llvm::zip(detectOps, valuesBefore)) {
866 if (!allDetectsAreAnyChange) {
867 if (!isa<IntType>(before.getType()))
868 return detectOp->emitError() <<
"requires int operand";
870 rewriter.setInsertionPoint(detectOp);
872 computeTrigger(before, detectOp.getInput(), detectOp.getEdge());
873 if (detectOp.getCondition()) {
874 auto condition = typeConverter->materializeTargetConversion(
875 rewriter, loc, rewriter.getI1Type(), detectOp.getCondition());
877 comb::AndOp::create(rewriter, loc, trigger, condition,
true);
879 triggers.push_back(trigger);
882 rewriter.eraseOp(detectOp);
885 rewriter.setInsertionPointToEnd(checkBlock);
886 if (triggers.empty()) {
891 cf::BranchOp::create(rewriter, loc, resumeBlock);
897 auto triggered = rewriter.createOrFold<
comb::OrOp>(loc, triggers,
true);
898 cf::CondBranchOp::create(rewriter, loc, triggered, resumeBlock,
907static LogicalResult
convert(WaitDelayOp op, WaitDelayOp::Adaptor adaptor,
908 ConversionPatternRewriter &rewriter) {
910 rewriter.splitBlock(op->getBlock(), ++Block::iterator(op));
911 rewriter.setInsertionPoint(op);
912 rewriter.replaceOpWithNewOp<llhd::WaitOp>(op, ValueRange{},
913 adaptor.getDelay(), ValueRange{},
914 ValueRange{}, resumeBlock);
915 rewriter.setInsertionPointToStart(resumeBlock);
920static LogicalResult
convert(UnreachableOp op, UnreachableOp::Adaptor adaptor,
921 ConversionPatternRewriter &rewriter) {
922 rewriter.replaceOpWithNewOp<llhd::HaltOp>(op, ValueRange{});
931 ConversionPatternRewriter &rewriter) {
933 if (isa<mlir::LLVM::LLVMPointerType>(type))
934 return mlir::LLVM::ZeroOp::create(rewriter, loc, type);
937 if (isa<llhd::TimeType>(type)) {
939 llhd::TimeAttr::get(type.getContext(), 0U, llvm::StringRef(
"ns"), 0, 0);
940 return llhd::ConstantTimeOp::create(rewriter, loc, timeAttr);
944 if (
auto floatType = dyn_cast<FloatType>(type)) {
945 auto floatAttr = rewriter.getFloatAttr(floatType, 0.0);
946 return mlir::arith::ConstantOp::create(rewriter, loc, floatAttr);
950 if (
auto strType = dyn_cast<sim::DynamicStringType>(type))
951 return sim::StringConstantOp::create(rewriter, loc, strType,
"");
954 if (
auto queueType = dyn_cast<sim::QueueType>(type))
955 return sim::QueueEmptyOp::create(rewriter, loc, queueType);
958 int64_t width = hw::getBitWidth(type);
966 return rewriter.createOrFold<
hw::BitcastOp>(loc, type, constZero);
969struct ClassPropertyRefOpConversion
971 ClassPropertyRefOpConversion(TypeConverter &tc, MLIRContext *ctx,
972 ClassTypeCache &cache)
976 matchAndRewrite(circt::moore::ClassPropertyRefOp op, OpAdaptor adaptor,
977 ConversionPatternRewriter &rewriter)
const override {
978 Location loc = op.getLoc();
979 MLIRContext *ctx = rewriter.getContext();
982 Type dstTy = getTypeConverter()->convertType(op.getPropertyRef().getType());
984 Value instRef = adaptor.getInstance();
988 cast<circt::moore::ClassHandleType>(op.getInstance().getType());
989 SymbolRefAttr classSym = classRefTy.getClassSym();
990 ModuleOp mod = op->getParentOfType<ModuleOp>();
991 if (failed(resolveClassStructBody(mod, classSym, *typeConverter, cache)))
992 return rewriter.notifyMatchFailure(op,
993 "Could not resolve class struct for " +
994 classSym.getRootReference().str());
996 auto structInfo = cache.getStructInfo(classSym);
997 assert(structInfo &&
"class struct info must exist");
998 auto structTy = structInfo->classBody;
1001 auto propSym = op.getProperty();
1002 auto pathOpt = structInfo->getFieldPath(propSym);
1004 return rewriter.notifyMatchFailure(op,
1005 "no GEP path for property " + propSym);
1007 auto i32Ty = IntegerType::get(ctx, 32);
1008 SmallVector<Value> idxVals;
1009 for (
unsigned idx : *pathOpt)
1010 idxVals.push_back(LLVM::ConstantOp::create(
1011 rewriter, loc, i32Ty, rewriter.getI32IntegerAttr(idx)));
1014 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
1016 LLVM::GEPOp::create(rewriter, loc, ptrTy, structTy, instRef, idxVals);
1019 Value fieldRef = UnrealizedConversionCastOp::create(rewriter, loc, dstTy,
1023 rewriter.replaceOp(op, fieldRef);
1028 ClassTypeCache &cache;
1032 using OpConversionPattern::OpConversionPattern;
1035 matchAndRewrite(ClassUpcastOp op, OpAdaptor adaptor,
1036 ConversionPatternRewriter &rewriter)
const override {
1038 Type dstTy = getTypeConverter()->convertType(op.getResult().getType());
1039 Type srcTy = adaptor.getInstance().getType();
1042 return rewriter.notifyMatchFailure(op,
"failed to convert result type");
1045 if (dstTy == srcTy && isa<LLVM::LLVMPointerType>(srcTy)) {
1046 rewriter.replaceOp(op, adaptor.getInstance());
1049 return rewriter.notifyMatchFailure(
1050 op,
"Upcast applied to non-opaque pointers!");
1056 ClassNewOpConversion(TypeConverter &tc, MLIRContext *ctx,
1057 ClassTypeCache &cache, FunctionCache &funcCache)
1059 funcCache(funcCache) {}
1062 matchAndRewrite(ClassNewOp op, OpAdaptor adaptor,
1063 ConversionPatternRewriter &rewriter)
const override {
1064 Location loc = op.getLoc();
1065 MLIRContext *ctx = rewriter.getContext();
1067 auto handleTy = cast<ClassHandleType>(op.getResult().getType());
1068 auto sym = handleTy.getClassSym();
1070 ModuleOp mod = op->getParentOfType<ModuleOp>();
1072 if (failed(resolveClassStructBody(mod, sym, *typeConverter, cache)))
1073 return op.emitError() <<
"Could not resolve class struct for " << sym;
1075 auto structTy = cache.getStructInfo(sym)->classBody;
1076 auto typeInfo = cache.getStructInfo(sym)->typeInfo;
1081 for (
auto memberTy : structTy.getBody()) {
1082 if (!LLVM::isCompatibleType(memberTy) &&
1083 !memberTy.hasTrait<DataLayoutTypeInterface::Trait>()) {
1084 return op.emitError()
1085 <<
"class struct has member types with no data layout";
1091 uint64_t byteSize = dl.getTypeSize(structTy);
1092 auto i64Ty = IntegerType::get(ctx, 64);
1093 auto cSize = LLVM::ConstantOp::create(rewriter, loc, i64Ty,
1094 rewriter.getI64IntegerAttr(byteSize));
1097 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
1098 auto mallocFn = funcCache.getOrCreate(rewriter,
"malloc", {i64Ty}, {ptrTy});
1100 func::CallOp::create(rewriter, loc, mallocFn, ValueRange{cSize});
1103 LLVM::AddressOfOp::create(rewriter, loc, typeInfo.global);
1104 auto i32Ty = IntegerType::get(ctx, 32);
1105 auto headerIdx = LLVM::ConstantOp::create(
1106 rewriter, loc, i32Ty,
1107 rewriter.getI32IntegerAttr(cache.getStructInfo(sym)->headerFieldIndex));
1108 auto typeInfoIdx = LLVM::ConstantOp::create(
1109 rewriter, loc, i32Ty,
1110 rewriter.getI32IntegerAttr(
1111 cache.getStructInfo(sym)->typeInfoFieldIndex));
1113 LLVM::GEPOp::create(rewriter, loc, ptrTy, structTy, call.getResult(0),
1114 ValueRange{headerIdx, typeInfoIdx});
1115 LLVM::StoreOp::create(rewriter, loc, typeInfoAddr, headerPtr);
1119 rewriter.replaceOp(op, call.getResult(0));
1124 ClassTypeCache &cache;
1125 FunctionCache &funcCache;
1129 ClassDeclOpConversion(TypeConverter &tc, MLIRContext *ctx,
1130 ClassTypeCache &cache)
1134 matchAndRewrite(ClassDeclOp op, OpAdaptor,
1135 ConversionPatternRewriter &rewriter)
const override {
1137 if (failed(resolveClassStructBody(op, *typeConverter, cache)))
1140 rewriter.eraseOp(op);
1145 ClassTypeCache &cache;
1149 using OpConversionPattern::OpConversionPattern;
1152 matchAndRewrite(VariableOp op, OpAdaptor adaptor,
1153 ConversionPatternRewriter &rewriter)
const override {
1154 auto loc = op.getLoc();
1155 auto resultType = typeConverter->convertType(op.getResult().getType());
1157 return rewriter.notifyMatchFailure(op.getLoc(),
"invalid variable type");
1160 Value init = adaptor.getInitial();
1162 auto refType = dyn_cast<llhd::RefType>(resultType);
1164 return rewriter.notifyMatchFailure(
1165 op.getLoc(),
"variable type did not convert to llhd::RefType");
1171 rewriter.replaceOpWithNewOp<llhd::SignalOp>(op, resultType,
1172 op.getNameAttr(), init);
1178 using OpConversionPattern::OpConversionPattern;
1181 matchAndRewrite(NetOp op, OpAdaptor adaptor,
1182 ConversionPatternRewriter &rewriter)
const override {
1183 auto loc = op.getLoc();
1185 auto resultType = typeConverter->convertType(op.getResult().getType());
1187 return rewriter.notifyMatchFailure(loc,
"invalid net type");
1189 auto elementType = cast<llhd::RefType>(resultType).getNestedType();
1195 createInitialValue(op.getKind(), rewriter, loc, width,
elementType);
1196 auto signal = rewriter.replaceOpWithNewOp<llhd::SignalOp>(
1197 op, resultType, op.getNameAttr(), init);
1199 if (
auto assignedValue = adaptor.getAssignment()) {
1200 auto timeAttr = llhd::TimeAttr::get(resultType.getContext(), 0U,
1201 llvm::StringRef(
"ns"), 0, 1);
1202 auto time = llhd::ConstantTimeOp::create(rewriter, loc, timeAttr);
1203 llhd::DriveOp::create(rewriter, loc, signal, assignedValue, time,
1210 static mlir::Value createInitialValue(NetKind kind,
1211 ConversionPatternRewriter &rewriter,
1212 Location loc, int64_t width,
1223 if (kind == NetKind::Supply1 || kind == NetKind::Tri1)
1224 return APInt::getAllOnes(width);
1225 return APInt::getZero(width);
1233static LogicalResult
convert(GlobalVariableOp op,
1234 GlobalVariableOp::Adaptor adaptor,
1235 ConversionPatternRewriter &rewriter,
1236 const TypeConverter &typeConverter) {
1237 auto type = typeConverter.convertType(op.getType());
1238 auto sig = llhd::GlobalSignalOp::create(rewriter, op.getLoc(),
1239 op.getSymNameAttr(), type);
1240 sig.getInitRegion().takeBody(op.getInitRegion());
1241 rewriter.eraseOp(op);
1246static LogicalResult
convert(GetGlobalVariableOp op,
1247 GetGlobalVariableOp::Adaptor adaptor,
1248 ConversionPatternRewriter &rewriter,
1249 const TypeConverter &typeConverter) {
1250 auto type = typeConverter.convertType(op.getType());
1251 rewriter.replaceOpWithNewOp<llhd::GetGlobalSignalOp>(op, type,
1252 op.getGlobalNameAttr());
1261 using OpConversionPattern::OpConversionPattern;
1264 matchAndRewrite(ConstantOp op, OpAdaptor adaptor,
1265 ConversionPatternRewriter &rewriter)
const override {
1267 auto value = op.getValue().toAPInt(
false);
1268 auto type = rewriter.getIntegerType(value.getBitWidth());
1270 op, type, rewriter.getIntegerAttr(type, value));
1276 using OpConversionPattern::OpConversionPattern;
1279 matchAndRewrite(ConstantRealOp op, OpAdaptor adaptor,
1280 ConversionPatternRewriter &rewriter)
const override {
1281 rewriter.replaceOpWithNewOp<arith::ConstantOp>(op, op.getValueAttr());
1287 using OpConversionPattern::OpConversionPattern;
1290 matchAndRewrite(ConstantTimeOp op, OpAdaptor adaptor,
1291 ConversionPatternRewriter &rewriter)
const override {
1292 rewriter.replaceOpWithNewOp<llhd::ConstantTimeOp>(
1293 op, llhd::TimeAttr::get(op->getContext(), op.getValue(),
1294 StringRef(
"fs"), 0, 0));
1300 using OpConversionPattern::OpConversionPattern;
1302 matchAndRewrite(moore::ConstantStringOp op, OpAdaptor adaptor,
1303 ConversionPatternRewriter &rewriter)
const override {
1304 const auto resultType =
1305 typeConverter->convertType(op.getResult().getType());
1306 const auto intType = mlir::cast<IntegerType>(resultType);
1308 const auto str = op.getValue();
1309 const unsigned byteWidth = intType.getWidth();
1310 APInt value(byteWidth, 0);
1313 const size_t maxChars =
1314 std::min(str.size(),
static_cast<size_t>(byteWidth / 8));
1315 for (
size_t i = 0; i < maxChars; i++) {
1316 const size_t pos = str.size() - 1 - i;
1317 const auto asciiChar =
static_cast<uint8_t
>(str[pos]);
1318 value |= APInt(byteWidth, asciiChar) << (8 * i);
1322 op, resultType, rewriter.getIntegerAttr(resultType, value));
1328 using OpConversionPattern::OpConversionPattern;
1330 matchAndRewrite(ConcatOp op, OpAdaptor adaptor,
1331 ConversionPatternRewriter &rewriter)
const override {
1332 rewriter.replaceOpWithNewOp<
comb::ConcatOp>(op, adaptor.getValues());
1338 using OpConversionPattern::OpConversionPattern;
1340 matchAndRewrite(ReplicateOp op, OpAdaptor adaptor,
1341 ConversionPatternRewriter &rewriter)
const override {
1342 Type resultType = typeConverter->convertType(op.getResult().getType());
1344 rewriter.replaceOpWithNewOp<comb::ReplicateOp>(op, resultType,
1345 adaptor.getValue());
1351 using OpConversionPattern::OpConversionPattern;
1354 matchAndRewrite(ExtractOp op, OpAdaptor adaptor,
1355 ConversionPatternRewriter &rewriter)
const override {
1358 Type resultType = typeConverter->convertType(op.getResult().getType());
1359 Type inputType = adaptor.getInput().getType();
1360 int32_t low = adaptor.getLowBit();
1362 if (isa<IntegerType>(inputType)) {
1363 int32_t inputWidth = inputType.getIntOrFloatBitWidth();
1364 int32_t resultWidth = hw::getBitWidth(resultType);
1365 int32_t high = low + resultWidth;
1367 SmallVector<Value> toConcat;
1370 rewriter, op.getLoc(), APInt(std::min(-low, resultWidth), 0)));
1372 if (low < inputWidth && high > 0) {
1373 int32_t lowIdx = std::max(low, 0);
1376 rewriter.getIntegerType(
1377 std::min(resultWidth, std::min(high, inputWidth) - lowIdx)),
1378 adaptor.getInput(), lowIdx);
1379 toConcat.push_back(middle);
1382 int32_t diff = high - inputWidth;
1386 toConcat.push_back(val);
1391 rewriter.replaceOp(op, concat);
1395 if (
auto arrTy = dyn_cast<hw::ArrayType>(inputType)) {
1396 int32_t width = llvm::Log2_64_Ceil(arrTy.getNumElements());
1397 int32_t inputWidth = arrTy.getNumElements();
1399 if (
auto resArrTy = dyn_cast<hw::ArrayType>(resultType);
1400 resArrTy && resArrTy != arrTy.getElementType()) {
1401 int32_t elementWidth = hw::getBitWidth(arrTy.getElementType());
1402 if (elementWidth < 0)
1405 int32_t high = low + resArrTy.getNumElements();
1406 int32_t resWidth = resArrTy.getNumElements();
1408 SmallVector<Value> toConcat;
1411 rewriter, op.getLoc(),
1412 APInt(std::min((-low) * elementWidth, resWidth * elementWidth),
1415 op.getLoc(), hw::ArrayType::get(arrTy.getElementType(), -low),
1417 toConcat.push_back(res);
1420 if (low < inputWidth && high > 0) {
1421 int32_t lowIdx = std::max(0, low);
1423 rewriter, op.getLoc(), rewriter.getIntegerType(width), lowIdx);
1427 arrTy.getElementType(),
1428 std::min(resWidth, std::min(inputWidth, high) - lowIdx)),
1429 adaptor.getInput(), lowIdxVal);
1430 toConcat.push_back(middle);
1433 int32_t diff = high - inputWidth;
1436 rewriter, op.getLoc(), APInt(diff * elementWidth, 0));
1438 rewriter, op.getLoc(),
1439 hw::ArrayType::get(arrTy.getElementType(), diff), constZero);
1440 toConcat.push_back(val);
1445 rewriter.replaceOp(op, concat);
1450 if (low < 0 || low >= inputWidth) {
1451 int32_t bw = hw::getBitWidth(resultType);
1457 rewriter.createOrFold<
hw::BitcastOp>(op.getLoc(), resultType, val);
1458 rewriter.replaceOp(op, bitcast);
1463 rewriter.getIntegerType(width),
1464 adaptor.getLowBit());
1465 rewriter.replaceOpWithNewOp<
hw::ArrayGetOp>(op, adaptor.getInput(), idx);
1474 using OpConversionPattern::OpConversionPattern;
1477 matchAndRewrite(ExtractRefOp op, OpAdaptor adaptor,
1478 ConversionPatternRewriter &rewriter)
const override {
1480 Type resultType = typeConverter->convertType(op.getResult().getType());
1482 cast<llhd::RefType>(adaptor.getInput().getType()).getNestedType();
1484 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1485 int64_t width = hw::getBitWidth(inputType);
1490 rewriter, op.getLoc(),
1491 rewriter.getIntegerType(llvm::Log2_64_Ceil(width)),
1492 adaptor.getLowBit());
1493 rewriter.replaceOpWithNewOp<llhd::SigExtractOp>(
1494 op, resultType, adaptor.getInput(), lowBit);
1498 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1500 rewriter, op.getLoc(),
1501 rewriter.getIntegerType(llvm::Log2_64_Ceil(arrType.getNumElements())),
1502 adaptor.getLowBit());
1506 if (arrType.getElementType() !=
1507 cast<llhd::RefType>(resultType).getNestedType()) {
1508 rewriter.replaceOpWithNewOp<llhd::SigArraySliceOp>(
1509 op, resultType, adaptor.getInput(), lowBit);
1513 rewriter.replaceOpWithNewOp<llhd::SigArrayGetOp>(op, adaptor.getInput(),
1523 using OpConversionPattern::OpConversionPattern;
1526 matchAndRewrite(DynExtractOp op, OpAdaptor adaptor,
1527 ConversionPatternRewriter &rewriter)
const override {
1528 Type resultType = typeConverter->convertType(op.getResult().getType());
1529 Type inputType = adaptor.getInput().getType();
1531 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1532 Value amount = adjustIntegerWidth(rewriter, adaptor.getLowBit(),
1533 intType.getWidth(), op->getLoc());
1534 Value value = comb::ShrUOp::create(rewriter, op->getLoc(),
1535 adaptor.getInput(), amount);
1537 rewriter.replaceOpWithNewOp<
comb::ExtractOp>(op, resultType, value, 0);
1541 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1542 unsigned idxWidth = llvm::Log2_64_Ceil(arrType.getNumElements());
1543 Value idx = adjustIntegerWidth(rewriter, adaptor.getLowBit(), idxWidth,
1546 bool isSingleElementExtract = arrType.getElementType() == resultType;
1548 if (isSingleElementExtract)
1549 rewriter.replaceOpWithNewOp<
hw::ArrayGetOp>(op, adaptor.getInput(),
1553 adaptor.getInput(), idx);
1563 using OpConversionPattern::OpConversionPattern;
1566 matchAndRewrite(DynExtractRefOp op, OpAdaptor adaptor,
1567 ConversionPatternRewriter &rewriter)
const override {
1569 Type resultType = typeConverter->convertType(op.getResult().getType());
1571 cast<llhd::RefType>(adaptor.getInput().getType()).getNestedType();
1573 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1574 int64_t width = hw::getBitWidth(inputType);
1579 adjustIntegerWidth(rewriter, adaptor.getLowBit(),
1580 llvm::Log2_64_Ceil(width), op->getLoc());
1581 rewriter.replaceOpWithNewOp<llhd::SigExtractOp>(
1582 op, resultType, adaptor.getInput(), amount);
1586 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1587 Value idx = adjustIntegerWidth(
1588 rewriter, adaptor.getLowBit(),
1589 llvm::Log2_64_Ceil(arrType.getNumElements()), op->getLoc());
1591 auto resultNestedType = cast<llhd::RefType>(resultType).getNestedType();
1592 bool isSingleElementExtract =
1593 arrType.getElementType() == resultNestedType;
1595 if (isSingleElementExtract)
1596 rewriter.replaceOpWithNewOp<llhd::SigArrayGetOp>(op, adaptor.getInput(),
1599 rewriter.replaceOpWithNewOp<llhd::SigArraySliceOp>(
1600 op, resultType, adaptor.getInput(), idx);
1610 using OpConversionPattern::OpConversionPattern;
1613 matchAndRewrite(ArrayCreateOp op, OpAdaptor adaptor,
1614 ConversionPatternRewriter &rewriter)
const override {
1615 Type resultType = typeConverter->convertType(op.getResult().getType());
1617 adaptor.getElements());
1623 using OpConversionPattern::OpConversionPattern;
1626 matchAndRewrite(StructCreateOp op, OpAdaptor adaptor,
1627 ConversionPatternRewriter &rewriter)
const override {
1628 Type resultType = typeConverter->convertType(op.getResult().getType());
1630 adaptor.getFields());
1636 using OpConversionPattern::OpConversionPattern;
1639 matchAndRewrite(StructExtractOp op, OpAdaptor adaptor,
1640 ConversionPatternRewriter &rewriter)
const override {
1642 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1647struct StructExtractRefOpConversion
1649 using OpConversionPattern::OpConversionPattern;
1652 matchAndRewrite(StructExtractRefOp op, OpAdaptor adaptor,
1653 ConversionPatternRewriter &rewriter)
const override {
1654 rewriter.replaceOpWithNewOp<llhd::SigStructExtractOp>(
1655 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1661 using OpConversionPattern::OpConversionPattern;
1664 matchAndRewrite(UnionCreateOp op, OpAdaptor adaptor,
1665 ConversionPatternRewriter &rewriter)
const override {
1666 Type resultType = typeConverter->convertType(op.getResult().getType());
1667 rewriter.replaceOpWithNewOp<hw::UnionCreateOp>(
1668 op, resultType, adaptor.getFieldNameAttr(), adaptor.getInput());
1674 using OpConversionPattern::OpConversionPattern;
1677 matchAndRewrite(UnionExtractOp op, OpAdaptor adaptor,
1678 ConversionPatternRewriter &rewriter)
const override {
1679 rewriter.replaceOpWithNewOp<hw::UnionExtractOp>(op, adaptor.getInput(),
1680 adaptor.getFieldNameAttr());
1685struct UnionExtractRefOpConversion
1687 using OpConversionPattern::OpConversionPattern;
1690 matchAndRewrite(UnionExtractRefOp op, OpAdaptor adaptor,
1691 ConversionPatternRewriter &rewriter)
const override {
1692 rewriter.replaceOpWithNewOp<llhd::SigStructExtractOp>(
1693 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1699 using OpConversionPattern::OpConversionPattern;
1701 matchAndRewrite(ReduceAndOp op, OpAdaptor adaptor,
1702 ConversionPatternRewriter &rewriter)
const override {
1703 Type resultType = typeConverter->convertType(op.getInput().getType());
1706 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::eq,
1707 adaptor.getInput(), max);
1713 using OpConversionPattern::OpConversionPattern;
1715 matchAndRewrite(ReduceOrOp op, OpAdaptor adaptor,
1716 ConversionPatternRewriter &rewriter)
const override {
1717 Type resultType = typeConverter->convertType(op.getInput().getType());
1720 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1721 adaptor.getInput(), zero);
1727 using OpConversionPattern::OpConversionPattern;
1729 matchAndRewrite(ReduceXorOp op, OpAdaptor adaptor,
1730 ConversionPatternRewriter &rewriter)
const override {
1732 rewriter.replaceOpWithNewOp<
comb::ParityOp>(op, adaptor.getInput());
1738 using OpConversionPattern::OpConversionPattern;
1740 matchAndRewrite(BoolCastOp op, OpAdaptor adaptor,
1741 ConversionPatternRewriter &rewriter)
const override {
1742 Type resultType = typeConverter->convertType(op.getInput().getType());
1743 if (isa_and_nonnull<IntegerType>(resultType)) {
1746 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1747 adaptor.getInput(), zero);
1750 if (isa_and_nonnull<FloatType>(resultType)) {
1751 Value zero = arith::ConstantOp::create(
1752 rewriter, op->getLoc(), rewriter.getFloatAttr(resultType, 0.0));
1753 rewriter.replaceOpWithNewOp<arith::CmpFOp>(op, arith::CmpFPredicate::ONE,
1754 adaptor.getInput(), zero);
1762 using OpConversionPattern::OpConversionPattern;
1764 matchAndRewrite(NotOp op, OpAdaptor adaptor,
1765 ConversionPatternRewriter &rewriter)
const override {
1767 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1770 rewriter.replaceOpWithNewOp<
comb::XorOp>(op, adaptor.getInput(), max);
1776 using OpConversionPattern::OpConversionPattern;
1778 matchAndRewrite(NegOp op, OpAdaptor adaptor,
1779 ConversionPatternRewriter &rewriter)
const override {
1781 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1784 rewriter.replaceOpWithNewOp<
comb::SubOp>(op, zero, adaptor.getInput());
1790 using OpConversionPattern::OpConversionPattern;
1792 matchAndRewrite(NegRealOp op, OpAdaptor adaptor,
1793 ConversionPatternRewriter &rewriter)
const override {
1794 rewriter.replaceOpWithNewOp<arith::NegFOp>(op, adaptor.getInput());
1799template <
typename SourceOp,
typename TargetOp>
1802 using OpAdaptor =
typename SourceOp::Adaptor;
1805 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1806 ConversionPatternRewriter &rewriter)
const override {
1807 rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(),
1808 adaptor.getRhs(),
false);
1813template <
typename SourceOp,
typename TargetOp>
1816 using OpAdaptor =
typename SourceOp::Adaptor;
1819 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1820 ConversionPatternRewriter &rewriter)
const override {
1821 rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(),
1827template <
typename SourceOp, ICmpPredicate pred>
1830 using OpAdaptor =
typename SourceOp::Adaptor;
1833 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1834 ConversionPatternRewriter &rewriter)
const override {
1836 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1838 rewriter.replaceOpWithNewOp<comb::ICmpOp>(
1839 op, resultType, pred, adaptor.getLhs(), adaptor.getRhs());
1844template <
typename SourceOp, arith::CmpFPredicate pred>
1847 using OpAdaptor =
typename SourceOp::Adaptor;
1850 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1851 ConversionPatternRewriter &rewriter)
const override {
1853 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1855 rewriter.replaceOpWithNewOp<arith::CmpFOp>(
1856 op, resultType, pred, adaptor.getLhs(), adaptor.getRhs());
1861template <
typename SourceOp,
bool withoutX>
1864 using OpAdaptor =
typename SourceOp::Adaptor;
1867 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1868 ConversionPatternRewriter &rewriter)
const override {
1874 unsigned bitWidth = op.getLhs().getType().getWidth();
1875 auto ignoredBits = APInt::getZero(bitWidth);
1876 auto detectIgnoredBits = [&](Value value) {
1877 auto constOp = value.getDefiningOp<ConstantOp>();
1880 auto constValue = constOp.getValue();
1882 ignoredBits |= constValue.getZBits();
1884 ignoredBits |= constValue.getUnknownBits();
1886 detectIgnoredBits(op.getLhs());
1887 detectIgnoredBits(op.getRhs());
1891 Value lhs = adaptor.getLhs();
1892 Value rhs = adaptor.getRhs();
1893 if (!ignoredBits.isZero()) {
1894 ignoredBits.flipAllBits();
1896 lhs = rewriter.createOrFold<
comb::AndOp>(op.getLoc(), lhs, maskOp);
1897 rhs = rewriter.createOrFold<
comb::AndOp>(op.getLoc(), rhs, maskOp);
1900 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, ICmpPredicate::ceq, lhs, rhs);
1910 using OpConversionPattern::OpConversionPattern;
1913 matchAndRewrite(ConversionOp op, OpAdaptor adaptor,
1914 ConversionPatternRewriter &rewriter)
const override {
1915 Location loc = op.getLoc();
1916 Type resultType = typeConverter->convertType(op.getResult().getType());
1918 op.emitError(
"conversion result type is not currently supported");
1921 int64_t inputBw = hw::getBitWidth(adaptor.getInput().getType());
1922 int64_t resultBw = hw::getBitWidth(resultType);
1923 if (inputBw == -1 || resultBw == -1) {
1924 if (isSupportedDpiOpenArrayCast(op.getInput().getType(),
1925 op.getResult().getType())) {
1926 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
1927 op, resultType, adaptor.getInput());
1930 if (hasOpenArrayBoundaryType(op.getInput().getType()) ||
1931 hasOpenArrayBoundaryType(op.getResult().getType())) {
1932 op.emitError(
"unsupported DPI open-array conversion from ")
1933 << op.getInput().getType() <<
" to " << op.getResult().getType();
1940 loc, rewriter.getIntegerType(inputBw), adaptor.getInput());
1941 Value amount = adjustIntegerWidth(rewriter, input, resultBw, loc);
1944 rewriter.createOrFold<
hw::BitcastOp>(loc, resultType, amount);
1945 rewriter.replaceOp(op, result);
1950template <
typename SourceOp>
1953 using OpAdaptor =
typename SourceOp::Adaptor;
1954 using ConversionPattern::typeConverter;
1957 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1958 ConversionPatternRewriter &rewriter)
const override {
1959 auto type = typeConverter->convertType(op.getResult().getType());
1960 if (type == adaptor.getInput().getType())
1961 rewriter.replaceOp(op, adaptor.getInput());
1963 rewriter.replaceOpWithNewOp<
hw::BitcastOp>(op, type, adaptor.getInput());
1969template <
typename SourceOp>
1972 using OpAdaptor =
typename SourceOp::Adaptor;
1973 using ConversionPattern::typeConverter;
1976 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1977 ConversionPatternRewriter &rewriter)
const override {
1978 rewriter.replaceOp(op, adaptor.getInput());
1984 using OpConversionPattern::OpConversionPattern;
1987 matchAndRewrite(TruncOp op, OpAdaptor adaptor,
1988 ConversionPatternRewriter &rewriter)
const override {
1989 rewriter.replaceOpWithNewOp<
comb::ExtractOp>(op, adaptor.getInput(), 0,
1990 op.getType().getWidth());
1996 using OpConversionPattern::OpConversionPattern;
1999 matchAndRewrite(ZExtOp op, OpAdaptor adaptor,
2000 ConversionPatternRewriter &rewriter)
const override {
2001 auto targetWidth = op.getType().getWidth();
2002 auto inputWidth = op.getInput().getType().getWidth();
2005 rewriter, op.getLoc(),
2006 rewriter.getIntegerType(targetWidth - inputWidth), 0);
2009 op, ValueRange{zeroExt, adaptor.getInput()});
2015 using OpConversionPattern::OpConversionPattern;
2018 matchAndRewrite(SExtOp op, OpAdaptor adaptor,
2019 ConversionPatternRewriter &rewriter)
const override {
2020 auto type = typeConverter->convertType(op.getType());
2022 comb::createOrFoldSExt(rewriter, op.getLoc(), adaptor.getInput(), type);
2023 rewriter.replaceOp(op, value);
2029 using OpConversionPattern::OpConversionPattern;
2032 matchAndRewrite(SIntToRealOp op, OpAdaptor adaptor,
2033 ConversionPatternRewriter &rewriter)
const override {
2034 rewriter.replaceOpWithNewOp<arith::SIToFPOp>(
2035 op, typeConverter->convertType(op.getType()), adaptor.getInput());
2041 using OpConversionPattern::OpConversionPattern;
2044 matchAndRewrite(UIntToRealOp op, OpAdaptor adaptor,
2045 ConversionPatternRewriter &rewriter)
const override {
2046 rewriter.replaceOpWithNewOp<arith::UIToFPOp>(
2047 op, typeConverter->convertType(op.getType()), adaptor.getInput());
2053 using OpConversionPattern::OpConversionPattern;
2056 matchAndRewrite(IntToStringOp op, OpAdaptor adaptor,
2057 ConversionPatternRewriter &rewriter)
const override {
2058 rewriter.replaceOpWithNewOp<sim::IntToStringOp>(op, adaptor.getInput());
2064 using OpConversionPattern::OpConversionPattern;
2067 matchAndRewrite(RealToIntOp op, OpAdaptor adaptor,
2068 ConversionPatternRewriter &rewriter)
const override {
2069 rewriter.replaceOpWithNewOp<arith::FPToSIOp>(
2070 op, typeConverter->convertType(op.getType()), adaptor.getInput());
2076 using OpConversionPattern::OpConversionPattern;
2079 matchAndRewrite(ConvertRealOp op, OpAdaptor adaptor,
2080 ConversionPatternRewriter &rewriter)
const override {
2081 op.getInput().getType().getWidth() < op.getResult().getType().getWidth()
2082 ? rewriter.replaceOpWithNewOp<arith::ExtFOp>(
2083 op, typeConverter->convertType(op.getType()), adaptor.getInput())
2084 : rewriter.replaceOpWithNewOp<arith::TruncFOp>(
2085 op, typeConverter->
convertType(op.getType()), adaptor.getInput());
2095 using OpConversionPattern::OpConversionPattern;
2098 matchAndRewrite(hw::InstanceOp op, OpAdaptor adaptor,
2099 ConversionPatternRewriter &rewriter)
const override {
2100 SmallVector<Type> convResTypes;
2101 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
2104 rewriter.replaceOpWithNewOp<hw::InstanceOp>(
2105 op, convResTypes, op.getInstanceName(), op.getModuleName(),
2106 adaptor.getOperands(), op.getArgNames(),
2107 op.getResultNames(),
2108 rewriter.getArrayAttr({}),
nullptr);
2115 using OpConversionPattern::OpConversionPattern;
2118 matchAndRewrite(func::ReturnOp op, OpAdaptor adaptor,
2119 ConversionPatternRewriter &rewriter)
const override {
2120 rewriter.replaceOpWithNewOp<func::ReturnOp>(op, adaptor.getOperands());
2126 using OpConversionPattern::OpConversionPattern;
2129 matchAndRewrite(func::CallOp op, OpAdaptor adaptor,
2130 ConversionPatternRewriter &rewriter)
const override {
2131 SmallVector<Type> convResTypes;
2132 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
2134 rewriter.replaceOpWithNewOp<func::CallOp>(
2135 op, adaptor.getCallee(), convResTypes, adaptor.getOperands());
2140struct FuncDPICallOpConversion
2142 using OpConversionPattern::OpConversionPattern;
2145 matchAndRewrite(moore::FuncDPICallOp op, OpAdaptor adaptor,
2146 ConversionPatternRewriter &rewriter)
const override {
2147 SmallVector<Type> convResTypes;
2148 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
2150 rewriter.replaceOpWithNewOp<sim::DPICallOp>(
2151 op, convResTypes, op.getCalleeAttr(), Value(),
2152 Value(), adaptor.getInputs());
2158 using OpConversionPattern::OpConversionPattern;
2161 matchAndRewrite(moore::DPIFuncOp op, OpAdaptor adaptor,
2162 ConversionPatternRewriter &rewriter)
const override {
2164 auto toDPIDir = [](moore::DPIArgDirection dir) -> sim::DPIDirection {
2166 case moore::DPIArgDirection::In:
2167 return sim::DPIDirection::Input;
2168 case moore::DPIArgDirection::Out:
2169 return sim::DPIDirection::Output;
2170 case moore::DPIArgDirection::InOut:
2171 return sim::DPIDirection::InOut;
2172 case moore::DPIArgDirection::Return:
2173 return sim::DPIDirection::Return;
2175 llvm_unreachable(
"unknown DPIArgDirection");
2179 auto dirs = op.getDpiArgDirs();
2180 auto names = op.getDpiArgNames();
2181 SmallVector<Type> argTypes;
2182 op.getDPIArgTypes(argTypes);
2184 SmallVector<sim::DPIArgument> dpiArguments;
2185 for (
auto [dirAttr, nameAttr, mooreType] :
2186 llvm::zip(dirs, names, argTypes)) {
2187 auto dir = toDPIDir(cast<moore::DPIArgDirectionAttr>(dirAttr).getValue());
2188 auto name = cast<StringAttr>(nameAttr);
2189 Type coreType = typeConverter->convertType(mooreType);
2191 return op.emitOpError(
"argument '")
2192 << name <<
"' has unsupported type " << mooreType;
2193 dpiArguments.push_back({name, coreType, dir});
2196 auto coreDPIFuncType =
2197 sim::DPIFunctionType::get(rewriter.getContext(), dpiArguments);
2198 auto simFunc = sim::DPIFuncOp::create(
2199 rewriter, op.getLoc(), op.getSymNameAttr(), coreDPIFuncType,
2200 op.getArgumentLocsAttr(), op.getVerilogNameAttr());
2201 SymbolTable::setSymbolVisibility(simFunc,
2202 SymbolTable::getSymbolVisibility(op));
2203 rewriter.eraseOp(op);
2208struct UnrealizedConversionCastConversion
2210 using OpConversionPattern::OpConversionPattern;
2213 matchAndRewrite(UnrealizedConversionCastOp op, OpAdaptor adaptor,
2214 ConversionPatternRewriter &rewriter)
const override {
2215 SmallVector<Type> convResTypes;
2216 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
2221 if (convResTypes == adaptor.getOperands().getTypes()) {
2222 rewriter.replaceOp(op, adaptor.getOperands());
2226 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
2227 op, convResTypes, adaptor.getOperands());
2233 using OpConversionPattern::OpConversionPattern;
2236 matchAndRewrite(ShlOp op, OpAdaptor adaptor,
2237 ConversionPatternRewriter &rewriter)
const override {
2238 Type resultType = typeConverter->convertType(op.getResult().getType());
2242 adjustIntegerWidth(rewriter, adaptor.getAmount(),
2243 resultType.getIntOrFloatBitWidth(), op->getLoc());
2244 rewriter.replaceOpWithNewOp<
comb::ShlOp>(op, resultType, adaptor.getValue(),
2251 using OpConversionPattern::OpConversionPattern;
2254 matchAndRewrite(ShrOp op, OpAdaptor adaptor,
2255 ConversionPatternRewriter &rewriter)
const override {
2256 Type resultType = typeConverter->convertType(op.getResult().getType());
2260 adjustIntegerWidth(rewriter, adaptor.getAmount(),
2261 resultType.getIntOrFloatBitWidth(), op->getLoc());
2263 op, resultType, adaptor.getValue(), amount,
false);
2269 using OpConversionPattern::OpConversionPattern;
2272 matchAndRewrite(PowUOp op, OpAdaptor adaptor,
2273 ConversionPatternRewriter &rewriter)
const override {
2274 Type resultType = typeConverter->convertType(op.getResult().getType());
2276 Location loc = op->getLoc();
2281 auto lhs = comb::ConcatOp::create(rewriter, loc, zeroVal, adaptor.getLhs());
2282 auto rhs = comb::ConcatOp::create(rewriter, loc, zeroVal, adaptor.getRhs());
2285 auto pow = mlir::math::IPowIOp::create(rewriter, loc, lhs, rhs);
2293 using OpConversionPattern::OpConversionPattern;
2296 matchAndRewrite(PowSOp op, OpAdaptor adaptor,
2297 ConversionPatternRewriter &rewriter)
const override {
2298 Type resultType = typeConverter->convertType(op.getResult().getType());
2302 rewriter.replaceOpWithNewOp<mlir::math::IPowIOp>(
2303 op, resultType, adaptor.getLhs(), adaptor.getRhs());
2309 using OpConversionPattern::OpConversionPattern;
2312 matchAndRewrite(AShrOp op, OpAdaptor adaptor,
2313 ConversionPatternRewriter &rewriter)
const override {
2314 Type resultType = typeConverter->convertType(op.getResult().getType());
2318 adjustIntegerWidth(rewriter, adaptor.getAmount(),
2319 resultType.getIntOrFloatBitWidth(), op->getLoc());
2321 op, resultType, adaptor.getValue(), amount,
false);
2327 using OpConversionPattern::OpConversionPattern;
2330 matchAndRewrite(ReadOp op, OpAdaptor adaptor,
2331 ConversionPatternRewriter &rewriter)
const override {
2332 rewriter.replaceOpWithNewOp<llhd::ProbeOp>(op, adaptor.getInput());
2337struct AssignedVariableOpConversion
2339 using OpConversionPattern::OpConversionPattern;
2342 matchAndRewrite(AssignedVariableOp op, OpAdaptor adaptor,
2343 ConversionPatternRewriter &rewriter)
const override {
2344 rewriter.replaceOpWithNewOp<hw::WireOp>(op, adaptor.getInput(),
2345 adaptor.getNameAttr());
2351static llhd::TimeAttr
2352getBlockingOrContinuousAssignDelay(mlir::MLIRContext *
context) {
2353 return llhd::TimeAttr::get(
context, 0U,
"ns", 0, 1);
2356template <
typename OpTy>
2359 using OpAdaptor =
typename OpTy::Adaptor;
2362 matchAndRewrite(OpTy op, OpAdaptor adaptor,
2363 ConversionPatternRewriter &rewriter)
const override {
2366 if constexpr (std::is_same_v<OpTy, ContinuousAssignOp> ||
2367 std::is_same_v<OpTy, BlockingAssignOp>) {
2368 delay = llhd::ConstantTimeOp::create(
2369 rewriter, op->getLoc(),
2370 getBlockingOrContinuousAssignDelay(op->getContext()));
2371 }
else if constexpr (std::is_same_v<OpTy, NonBlockingAssignOp>) {
2373 delay = llhd::ConstantTimeOp::create(
2374 rewriter, op->getLoc(),
2375 llhd::TimeAttr::get(op->getContext(), 0U,
"ns", 1, 0));
2378 delay = adaptor.getDelay();
2381 rewriter.replaceOpWithNewOp<llhd::DriveOp>(
2382 op, adaptor.getDst(), adaptor.getSrc(), delay, Value{});
2388 using OpConversionPattern::OpConversionPattern;
2391 matchAndRewrite(ConditionalOp op, OpAdaptor adaptor,
2392 ConversionPatternRewriter &rewriter)
const override {
2397 auto type = typeConverter->convertType(op.getType());
2399 auto hasNoWriteEffect = [](Region ®ion) {
2400 auto result = region.walk([](Operation *operation) {
2401 if (
auto memOp = dyn_cast<MemoryEffectOpInterface>(operation))
2402 if (!memOp.hasEffect<MemoryEffects::Write>() &&
2403 !memOp.hasEffect<MemoryEffects::Free>())
2404 return WalkResult::advance();
2406 if (operation->hasTrait<OpTrait::HasRecursiveMemoryEffects>())
2407 return WalkResult::advance();
2409 return WalkResult::interrupt();
2411 return !result.wasInterrupted();
2414 if (hasNoWriteEffect(op.getTrueRegion()) &&
2415 hasNoWriteEffect(op.getFalseRegion())) {
2416 Operation *trueTerm = op.getTrueRegion().front().getTerminator();
2417 Operation *falseTerm = op.getFalseRegion().front().getTerminator();
2419 rewriter.inlineBlockBefore(&op.getTrueRegion().front(), op);
2420 rewriter.inlineBlockBefore(&op.getFalseRegion().front(), op);
2422 Value convTrueVal = typeConverter->materializeTargetConversion(
2423 rewriter, op.getLoc(), type, trueTerm->getOperand(0));
2424 Value convFalseVal = typeConverter->materializeTargetConversion(
2425 rewriter, op.getLoc(), type, falseTerm->getOperand(0));
2427 rewriter.eraseOp(trueTerm);
2428 rewriter.eraseOp(falseTerm);
2430 rewriter.replaceOpWithNewOp<
comb::MuxOp>(op, adaptor.getCondition(),
2431 convTrueVal, convFalseVal);
2436 scf::IfOp::create(rewriter, op.getLoc(), type, adaptor.getCondition());
2437 rewriter.inlineRegionBefore(op.getTrueRegion(), ifOp.getThenRegion(),
2438 ifOp.getThenRegion().end());
2439 rewriter.inlineRegionBefore(op.getFalseRegion(), ifOp.getElseRegion(),
2440 ifOp.getElseRegion().end());
2441 rewriter.replaceOp(op, ifOp);
2447 using OpConversionPattern::OpConversionPattern;
2450 matchAndRewrite(YieldOp op, OpAdaptor adaptor,
2451 ConversionPatternRewriter &rewriter)
const override {
2452 Operation *parent = op->getParentOp();
2453 if (isa<llhd::GlobalSignalOp>(parent))
2454 rewriter.replaceOpWithNewOp<llhd::YieldOp>(op, adaptor.getResult());
2455 else if (isa<scf::ExecuteRegionOp, scf::ForOp, scf::IfOp,
2456 scf::IndexSwitchOp, scf::WhileOp>(parent))
2457 rewriter.replaceOpWithNewOp<scf::YieldOp>(op, adaptor.getResult());
2459 return rewriter.notifyMatchFailure(
2460 op,
"yield parent has not been converted to a legal region op yet");
2465template <
typename SourceOp>
2468 using OpAdaptor =
typename SourceOp::Adaptor;
2471 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
2472 ConversionPatternRewriter &rewriter)
const override {
2473 rewriter.modifyOpInPlace(op,
2474 [&]() { op->setOperands(adaptor.getOperands()); });
2479template <
typename MooreOpTy,
typename VerifOpTy>
2482 using OpAdaptor =
typename MooreOpTy::Adaptor;
2485 matchAndRewrite(MooreOpTy op, OpAdaptor adaptor,
2486 ConversionPatternRewriter &rewriter)
const override {
2488 op.getLabel().has_value()
2489 ? StringAttr::get(op->getContext(), op.getLabel().value())
2490 : StringAttr::
get(op->getContext());
2491 rewriter.replaceOpWithNewOp<VerifOpTy>(op, adaptor.getCond(), mlir::Value(),
2502 using OpConversionPattern::OpConversionPattern;
2505 matchAndRewrite(FormatLiteralOp op, OpAdaptor adaptor,
2506 ConversionPatternRewriter &rewriter)
const override {
2507 rewriter.replaceOpWithNewOp<sim::FormatLiteralOp>(op, adaptor.getLiteral());
2513 using OpConversionPattern::OpConversionPattern;
2516 matchAndRewrite(FormatStringOp op, OpAdaptor adaptor,
2517 ConversionPatternRewriter &rewriter)
const override {
2519 op.getPadding().value_or(IntPadding::Space) == IntPadding::Space ? 32
2521 IntegerAttr padCharAttr = rewriter.getI8IntegerAttr(padChar);
2522 auto widthAttr = adaptor.getWidthAttr();
2524 bool isLeftAligned =
2525 op.getAlignment().value_or(IntAlign::Right) == IntAlign::Left;
2526 BoolAttr isLeftAlignedAttr = rewriter.getBoolAttr(isLeftAligned);
2528 rewriter.replaceOpWithNewOp<sim::FormatStringOp>(
2529 op, adaptor.getString(), isLeftAlignedAttr, padCharAttr, widthAttr);
2535 using OpConversionPattern::OpConversionPattern;
2538 matchAndRewrite(FormatConcatOp op, OpAdaptor adaptor,
2539 ConversionPatternRewriter &rewriter)
const override {
2540 rewriter.replaceOpWithNewOp<sim::FormatStringConcatOp>(op,
2541 adaptor.getInputs());
2546struct FormatHierPathOpConversion
2548 using OpConversionPattern::OpConversionPattern;
2551 matchAndRewrite(FormatHierPathOp op, OpAdaptor adaptor,
2552 ConversionPatternRewriter &rewriter)
const override {
2553 rewriter.replaceOpWithNewOp<sim::FormatHierPathOp>(op,
2554 adaptor.getUseEscapes());
2560 using OpConversionPattern::OpConversionPattern;
2563 matchAndRewrite(FormatIntOp op, OpAdaptor adaptor,
2564 ConversionPatternRewriter &rewriter)
const override {
2566 char padChar = adaptor.getPadding() == IntPadding::Space ? 32 : 48;
2567 IntegerAttr padCharAttr = rewriter.getI8IntegerAttr(padChar);
2568 auto widthAttr = adaptor.getSpecifierWidthAttr();
2570 bool isLeftAligned = adaptor.getAlignment() == IntAlign::Left;
2571 BoolAttr isLeftAlignedAttr = rewriter.getBoolAttr(isLeftAligned);
2573 switch (op.getFormat()) {
2574 case IntFormat::Decimal:
2575 rewriter.replaceOpWithNewOp<sim::FormatDecOp>(
2576 op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr,
2577 adaptor.getIsSignedAttr());
2579 case IntFormat::Binary:
2580 rewriter.replaceOpWithNewOp<sim::FormatBinOp>(
2581 op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr);
2583 case IntFormat::Octal:
2584 rewriter.replaceOpWithNewOp<sim::FormatOctOp>(
2585 op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr);
2587 case IntFormat::HexLower:
2588 rewriter.replaceOpWithNewOp<sim::FormatHexOp>(
2589 op, adaptor.getValue(), rewriter.getBoolAttr(
false),
2590 isLeftAlignedAttr, padCharAttr, widthAttr);
2592 case IntFormat::HexUpper:
2593 rewriter.replaceOpWithNewOp<sim::FormatHexOp>(
2594 op, adaptor.getValue(), rewriter.getBoolAttr(
true), isLeftAlignedAttr,
2595 padCharAttr, widthAttr);
2598 return rewriter.notifyMatchFailure(op,
"unsupported int format");
2603 using OpConversionPattern::OpConversionPattern;
2606 matchAndRewrite(FormatRealOp op, OpAdaptor adaptor,
2607 ConversionPatternRewriter &rewriter)
const override {
2608 auto fracDigitsAttr = adaptor.getFracDigitsAttr();
2610 auto fieldWidthAttr = adaptor.getFieldWidthAttr();
2611 bool isLeftAligned = adaptor.getAlignment() == IntAlign::Left;
2612 mlir::BoolAttr isLeftAlignedAttr = rewriter.getBoolAttr(isLeftAligned);
2614 switch (op.getFormat()) {
2615 case RealFormat::General:
2616 rewriter.replaceOpWithNewOp<sim::FormatGeneralOp>(
2617 op, adaptor.getValue(), isLeftAlignedAttr, fieldWidthAttr,
2620 case RealFormat::Float:
2621 rewriter.replaceOpWithNewOp<sim::FormatFloatOp>(
2622 op, adaptor.getValue(), isLeftAlignedAttr, fieldWidthAttr,
2625 case RealFormat::Exponential:
2626 rewriter.replaceOpWithNewOp<sim::FormatScientificOp>(
2627 op, adaptor.getValue(), isLeftAlignedAttr, fieldWidthAttr,
2634struct FormatCharOpConversion
2636 using OpConversionPattern::OpConversionPattern;
2638 matchAndRewrite(moore::FormatCharOp op, OpAdaptor adaptor,
2639 ConversionPatternRewriter &rewriter)
const override {
2640 rewriter.replaceOpWithNewOp<sim::FormatCharOp>(op, adaptor.getValue());
2646 using OpConversionPattern::OpConversionPattern;
2649 matchAndRewrite(StringLenOp op, OpAdaptor adaptor,
2650 ConversionPatternRewriter &rewriter)
const override {
2651 rewriter.replaceOpWithNewOp<sim::StringLengthOp>(op, adaptor.getStr());
2657 using OpConversionPattern::OpConversionPattern;
2660 matchAndRewrite(StringConcatOp op, OpAdaptor adaptor,
2661 ConversionPatternRewriter &rewriter)
const override {
2662 rewriter.replaceOpWithNewOp<sim::StringConcatOp>(op, adaptor.getInputs());
2668 using OpConversionPattern::OpConversionPattern;
2671 matchAndRewrite(StringGetOp op, OpAdaptor adaptor,
2672 ConversionPatternRewriter &rewriter)
const override {
2673 rewriter.replaceOpWithNewOp<sim::StringGetOp>(op, adaptor.getStr(),
2674 adaptor.getIndex());
2680 using OpConversionPattern::OpConversionPattern;
2683 matchAndRewrite(QueueSizeBIOp op, OpAdaptor adaptor,
2684 ConversionPatternRewriter &rewriter)
const override {
2685 rewriter.replaceOpWithNewOp<sim::QueueSizeOp>(op, adaptor.getQueue());
2690struct DynQueueExtractOpConversion
2692 using OpConversionPattern::OpConversionPattern;
2695 matchAndRewrite(DynQueueExtractOp op, OpAdaptor adaptor,
2696 ConversionPatternRewriter &rewriter)
const override {
2697 bool isSingleElementExtract =
2698 op.getInput().getType().getElementType() == op.getResult().getType();
2700 if (isSingleElementExtract) {
2701 rewriter.replaceOpWithNewOp<sim::QueueGetOp>(op, adaptor.getInput(),
2702 adaptor.getLowerIdx());
2704 rewriter.replaceOpWithNewOp<sim::QueueSliceOp>(
2705 op, adaptor.getInput(), adaptor.getLowerIdx(), adaptor.getUpperIdx());
2721probeRefAndDriveWithResult(OpBuilder &builder, Location loc, Value ref,
2722 const std::function<Value(Value)> &func) {
2724 Value v = llhd::ProbeOp::create(builder, loc, ref);
2727 Value delay = llhd::ConstantTimeOp::create(
2728 builder, loc, getBlockingOrContinuousAssignDelay(builder.getContext()));
2730 llhd::DriveOp::create(builder, loc, ref, func(v), delay, Value{});
2734 using OpConversionPattern::OpConversionPattern;
2737 matchAndRewrite(QueuePushBackOp op, OpAdaptor adaptor,
2738 ConversionPatternRewriter &rewriter)
const override {
2739 probeRefAndDriveWithResult(
2740 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2741 return sim::QueuePushBackOp::create(rewriter, op->getLoc(), queue,
2742 adaptor.getElement());
2745 rewriter.eraseOp(op);
2750struct QueuePushFrontOpConversion
2752 using OpConversionPattern::OpConversionPattern;
2755 matchAndRewrite(QueuePushFrontOp op, OpAdaptor adaptor,
2756 ConversionPatternRewriter &rewriter)
const override {
2758 probeRefAndDriveWithResult(
2759 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2760 return sim::QueuePushFrontOp::create(rewriter, op->getLoc(), queue,
2761 adaptor.getElement());
2764 rewriter.eraseOp(op);
2770 using OpConversionPattern::OpConversionPattern;
2773 matchAndRewrite(QueuePopBackOp op, OpAdaptor adaptor,
2774 ConversionPatternRewriter &rewriter)
const override {
2776 probeRefAndDriveWithResult(
2777 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2779 sim::QueuePopBackOp::create(rewriter, op->getLoc(), queue);
2780 popped = popBack.getPopped();
2781 return popBack.getOutQueue();
2783 rewriter.replaceOp(op, popped);
2790 using OpConversionPattern::OpConversionPattern;
2793 matchAndRewrite(QueuePopFrontOp op, OpAdaptor adaptor,
2794 ConversionPatternRewriter &rewriter)
const override {
2796 probeRefAndDriveWithResult(
2797 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2799 sim::QueuePopFrontOp::create(rewriter, op->getLoc(), queue);
2800 popped = popFront.getPopped();
2801 return popFront.getOutQueue();
2803 rewriter.replaceOp(op, popped);
2810 using OpConversionPattern::OpConversionPattern;
2813 matchAndRewrite(QueueClearOp op, OpAdaptor adaptor,
2814 ConversionPatternRewriter &rewriter)
const override {
2815 auto refType = cast<llhd::RefType>(adaptor.getQueue().getType());
2816 auto queueType = refType.getNestedType();
2818 sim::QueueEmptyOp::create(rewriter, op->getLoc(), queueType);
2821 Value delay = llhd::ConstantTimeOp::create(
2822 rewriter, op.getLoc(),
2823 getBlockingOrContinuousAssignDelay(rewriter.getContext()));
2825 llhd::DriveOp::create(rewriter, op.getLoc(), adaptor.getQueue(), emptyQueue,
2828 rewriter.eraseOp(op);
2834 using OpConversionPattern::OpConversionPattern;
2837 matchAndRewrite(QueueInsertOp op, OpAdaptor adaptor,
2838 ConversionPatternRewriter &rewriter)
const override {
2839 probeRefAndDriveWithResult(
2840 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2842 sim::QueueInsertOp::create(rewriter, op->getLoc(), queue,
2843 adaptor.getIndex(), adaptor.getItem());
2845 return insert.getOutQueue();
2847 rewriter.eraseOp(op);
2854 using OpConversionPattern::OpConversionPattern;
2857 matchAndRewrite(QueueDeleteOp op, OpAdaptor adaptor,
2858 ConversionPatternRewriter &rewriter)
const override {
2859 probeRefAndDriveWithResult(
2860 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2861 auto delOp = sim::QueueDeleteOp::create(rewriter, op->getLoc(), queue,
2862 adaptor.getIndex());
2864 return delOp.getOutQueue();
2866 rewriter.eraseOp(op);
2873 using OpConversionPattern::OpConversionPattern;
2876 matchAndRewrite(QueueResizeOp op, OpAdaptor adaptor,
2877 ConversionPatternRewriter &rewriter)
const override {
2879 rewriter.replaceOpWithNewOp<sim::QueueResizeOp>(
2880 op, getTypeConverter()->convertType(op.getResult().getType()),
2881 adaptor.getInput());
2887 using OpConversionPattern::OpConversionPattern;
2889 matchAndRewrite(QueueSetOp op, OpAdaptor adaptor,
2890 ConversionPatternRewriter &rewriter)
const override {
2891 probeRefAndDriveWithResult(
2892 rewriter, op->getLoc(), adaptor.getQueue(), [&](Value queue) {
2894 sim::QueueSetOp::create(rewriter, op.getLoc(), queue,
2895 adaptor.getIndex(), adaptor.getItem());
2896 return setOp.getOutQueue();
2898 rewriter.eraseOp(op);
2904 using OpConversionPattern::OpConversionPattern;
2907 matchAndRewrite(QueueCmpOp op, OpAdaptor adaptor,
2908 ConversionPatternRewriter &rewriter)
const override {
2916 auto unpackedPred = adaptor.getPredicateAttr().getValue();
2917 sim::QueueCmpPredicate queuePred;
2918 switch (unpackedPred) {
2919 case circt::moore::UArrayCmpPredicate::eq:
2920 queuePred = sim::QueueCmpPredicate::eq;
2922 case circt::moore::UArrayCmpPredicate::ne:
2923 queuePred = sim::QueueCmpPredicate::ne;
2927 auto cmpPred = sim::QueueCmpPredicateAttr::get(getContext(), queuePred);
2929 rewriter.replaceOpWithNewOp<sim::QueueCmpOp>(op, cmpPred, adaptor.getLhs(),
2935struct QueueFromUnpackedArrayOpConversion
2937 using OpConversionPattern::OpConversionPattern;
2940 matchAndRewrite(QueueFromUnpackedArrayOp op, OpAdaptor adaptor,
2941 ConversionPatternRewriter &rewriter)
const override {
2942 rewriter.replaceOpWithNewOp<sim::QueueFromArrayOp>(
2943 op, getTypeConverter()->convertType(op.getResult().getType()),
2944 adaptor.getInput());
2950 using OpConversionPattern::OpConversionPattern;
2953 matchAndRewrite(QueueConcatOp op, OpAdaptor adaptor,
2954 ConversionPatternRewriter &rewriter)
const override {
2955 rewriter.replaceOpWithNewOp<sim::QueueConcatOp>(
2956 op, getTypeConverter()->convertType(op.getResult().getType()),
2957 adaptor.getInputs());
2963 using OpConversionPattern::OpConversionPattern;
2966 matchAndRewrite(DisplayBIOp op, OpAdaptor adaptor,
2967 ConversionPatternRewriter &rewriter)
const override {
2968 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(
2969 op, adaptor.getMessage());
2975 using OpConversionPattern::OpConversionPattern;
2977 matchAndRewrite(FDisplayBIOp op, OpAdaptor adaptor,
2978 ConversionPatternRewriter &rewriter)
const override {
2979 auto stream = sim::SVChannelToOutputStreamOp::create(rewriter, op.getLoc(),
2981 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(
2982 op, adaptor.getMessage(), stream.getStream());
2988 using OpConversionPattern::OpConversionPattern;
2990 matchAndRewrite(FOpenBIOp op, OpAdaptor adaptor,
2991 ConversionPatternRewriter &rewriter)
const override {
2992 sim::SVFOpenModeAttr simMode;
2993 if (
auto modeAttr = op.getModeAttr()) {
2994 auto mapMode = [](moore::FOpenMode m) -> sim::SVFOpenMode {
2996 case moore::FOpenMode::Read:
2997 return sim::SVFOpenMode::Read;
2998 case moore::FOpenMode::Write:
2999 return sim::SVFOpenMode::Write;
3000 case moore::FOpenMode::Append:
3001 return sim::SVFOpenMode::Append;
3002 case moore::FOpenMode::ReadUpdate:
3003 return sim::SVFOpenMode::ReadUpdate;
3004 case moore::FOpenMode::WriteUpdate:
3005 return sim::SVFOpenMode::WriteUpdate;
3006 case moore::FOpenMode::AppendUpdate:
3007 return sim::SVFOpenMode::AppendUpdate;
3009 llvm_unreachable(
"unknown FOpenMode");
3011 simMode = sim::SVFOpenModeAttr::get(op.getContext(),
3012 mapMode(modeAttr.getValue()));
3014 rewriter.replaceOpWithNewOp<sim::SVFOpenOp>(op, adaptor.getFilename(),
3020struct PlusArgsTestBIOpConversion
3022 using OpConversionPattern::OpConversionPattern;
3024 matchAndRewrite(PlusArgsTestBIOp op, OpAdaptor adaptor,
3025 ConversionPatternRewriter &rewriter)
const override {
3026 rewriter.replaceOpWithNewOp<sim::PlusArgsTestOp>(op, rewriter.getI1Type(),
3027 op.getFormatStringAttr());
3032struct PlusArgsValueBIOpConversion
3034 using OpConversionPattern::OpConversionPattern;
3036 matchAndRewrite(PlusArgsValueBIOp op, OpAdaptor adaptor,
3037 ConversionPatternRewriter &rewriter)
const override {
3038 auto resultType = typeConverter->convertType(op.getResult().getType());
3040 return rewriter.notifyMatchFailure(op,
"unsupported result type");
3041 rewriter.replaceOpWithNewOp<sim::PlusArgsValueOp>(
3042 op, rewriter.getI1Type(), resultType, op.getFormatStringAttr());
3048 using OpConversionPattern::OpConversionPattern;
3051 matchAndRewrite(FCloseBIOp op, OpAdaptor adaptor,
3052 ConversionPatternRewriter &rewriter)
const override {
3053 rewriter.replaceOpWithNewOp<sim::SVFCloseOp>(op, adaptor.getFd());
3059 using OpConversionPattern::OpConversionPattern;
3062 matchAndRewrite(FFlushBIOp op, OpAdaptor adaptor,
3063 ConversionPatternRewriter &rewriter)
const override {
3064 if (!adaptor.getFd()) {
3065 rewriter.replaceOpWithNewOp<sim::SVFFlushAllOp>(op);
3067 auto stream = sim::SVChannelToOutputStreamOp::create(
3068 rewriter, op.getLoc(), adaptor.getFd());
3069 rewriter.replaceOpWithNewOp<sim::FlushOp>(op, stream);
3082static LogicalResult
convert(StopBIOp op, StopBIOp::Adaptor adaptor,
3083 ConversionPatternRewriter &rewriter) {
3084 rewriter.replaceOpWithNewOp<sim::PauseOp>(op,
false);
3089static LogicalResult
convert(FinishBIOp op, FinishBIOp::Adaptor adaptor,
3090 ConversionPatternRewriter &rewriter) {
3091 rewriter.replaceOpWithNewOp<sim::TerminateOp>(op, op.getExitCode() == 0,
3097static LogicalResult
convert(SeverityBIOp op, SeverityBIOp::Adaptor adaptor,
3098 ConversionPatternRewriter &rewriter) {
3100 std::string severityString;
3102 switch (op.getSeverity()) {
3103 case (Severity::Fatal):
3104 severityString =
"Fatal: ";
3106 case (Severity::Error):
3107 severityString =
"Error: ";
3109 case (Severity::Warning):
3110 severityString =
"Warning: ";
3112 case (Severity::Info):
3113 severityString =
"Info: ";
3118 sim::FormatLiteralOp::create(rewriter, op.getLoc(), severityString);
3119 auto message = sim::FormatStringConcatOp::create(
3120 rewriter, op.getLoc(), ValueRange{prefix, adaptor.getMessage()});
3121 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(op, message);
3135 UrandomRangeBIOp::Adaptor adaptor,
3136 ConversionPatternRewriter &rewriter,
3137 FunctionCache &funcCache) {
3138 auto loc = op.getLoc();
3139 auto i32Ty = rewriter.getI32Type();
3140 auto ptrTy = LLVM::LLVMPointerType::get(rewriter.getContext());
3141 auto fn = funcCache.getOrCreate(rewriter,
"__circt_urandom_range",
3142 {i32Ty, i32Ty, ptrTy}, {i32Ty});
3145 if (
auto seedRef = adaptor.getSeed()) {
3148 seedPtr = LLVM::AllocaOp::create(rewriter, loc, ptrTy, i32Ty, one);
3149 auto seedVal = llhd::ProbeOp::create(rewriter, loc, seedRef);
3150 LLVM::StoreOp::create(rewriter, loc, seedVal, seedPtr);
3152 seedPtr = LLVM::ZeroOp::create(rewriter, loc, ptrTy);
3155 auto call = func::CallOp::create(
3157 ValueRange{adaptor.getMinval(), adaptor.getMaxval(), seedPtr});
3160 if (adaptor.getSeed()) {
3161 auto newSeed = LLVM::LoadOp::create(rewriter, loc, i32Ty, seedPtr);
3162 auto epsilon = llhd::ConstantTimeOp::create(
3164 llhd::TimeAttr::get(rewriter.getContext(), 0,
"ns", 0, 1));
3165 llhd::DriveOp::create(rewriter, loc, adaptor.getSeed(), newSeed, epsilon,
3169 rewriter.replaceOp(op, call.getResult(0));
3175 FinishMessageBIOp::Adaptor adaptor,
3176 ConversionPatternRewriter &rewriter) {
3178 rewriter.eraseOp(op);
3187static LogicalResult
convert(TimeBIOp op, TimeBIOp::Adaptor adaptor,
3188 ConversionPatternRewriter &rewriter) {
3189 rewriter.replaceOpWithNewOp<llhd::CurrentTimeOp>(op);
3194static LogicalResult
convert(LogicToTimeOp op, LogicToTimeOp::Adaptor adaptor,
3195 ConversionPatternRewriter &rewriter) {
3196 rewriter.replaceOpWithNewOp<llhd::IntToTimeOp>(op, adaptor.getInput());
3201static LogicalResult
convert(TimeToLogicOp op, TimeToLogicOp::Adaptor adaptor,
3202 ConversionPatternRewriter &rewriter) {
3203 rewriter.replaceOpWithNewOp<llhd::TimeToIntOp>(op, adaptor.getInput());
3212 const TypeConverter &converter) {
3213 target.addIllegalDialect<MooreDialect>();
3214 target.addLegalDialect<comb::CombDialect>();
3215 target.addLegalDialect<hw::HWDialect>();
3216 target.addLegalDialect<seq::SeqDialect>();
3217 target.addLegalDialect<llhd::LLHDDialect>();
3218 target.addLegalDialect<ltl::LTLDialect>();
3219 target.addLegalDialect<mlir::BuiltinDialect>();
3220 target.addLegalDialect<mlir::math::MathDialect>();
3221 target.addLegalDialect<sim::SimDialect>();
3222 target.addLegalDialect<mlir::LLVM::LLVMDialect>();
3223 target.addLegalDialect<verif::VerifDialect>();
3224 target.addLegalDialect<arith::ArithDialect>();
3226 target.addLegalOp<debug::ScopeOp>();
3228 target.addDynamicallyLegalOp<scf::YieldOp, func::CallOp, func::ReturnOp,
3229 UnrealizedConversionCastOp, hw::OutputOp,
3230 hw::InstanceOp, debug::ArrayOp, debug::StructOp,
3231 debug::VariableOp, arith::SelectOp>(
3232 [&](Operation *op) {
return converter.isLegal(op); });
3234 target.addDynamicallyLegalOp<scf::IfOp, scf::ForOp, scf::ExecuteRegionOp,
3235 scf::WhileOp, scf::ForallOp>([&](Operation *op) {
3236 return converter.isLegal(op) && !op->getParentOfType<llhd::ProcessOp>();
3239 target.addDynamicallyLegalOp<func::FuncOp>([&](func::FuncOp op) {
3240 return converter.isSignatureLegal(op.getFunctionType());
3244 return converter.isSignatureLegal(op.getModuleType().getFuncType()) &&
3245 converter.isLegal(&op.getBody());
3250 typeConverter.addConversion([&](IntType type) {
3251 return IntegerType::get(type.getContext(), type.getWidth());
3254 typeConverter.addConversion([&](RealType type) -> mlir::Type {
3255 MLIRContext *ctx = type.getContext();
3256 switch (type.getWidth()) {
3257 case moore::RealWidth::f32:
3258 return mlir::Float32Type::get(ctx);
3259 case moore::RealWidth::f64:
3260 return mlir::Float64Type::get(ctx);
3264 typeConverter.addConversion(
3265 [&](TimeType type) {
return llhd::TimeType::get(type.getContext()); });
3267 typeConverter.addConversion([&](FormatStringType type) {
3268 return sim::FormatStringType::get(type.getContext());
3271 typeConverter.addConversion([&](StringType type) {
3272 return sim::DynamicStringType::get(type.getContext());
3275 typeConverter.addConversion([&](QueueType type) {
3276 return sim::QueueType::get(type.getContext(),
3277 typeConverter.convertType(type.getElementType()),
3281 typeConverter.addConversion([&](ArrayType type) -> std::optional<Type> {
3282 if (
auto elementType = typeConverter.convertType(type.getElementType()))
3283 return hw::ArrayType::get(
elementType, type.getSize());
3290 typeConverter.addConversion(
3291 [&](UnpackedArrayType type) -> std::optional<Type> {
3292 if (
auto elementType = typeConverter.convertType(type.getElementType()))
3293 return hw::ArrayType::get(
elementType, type.getSize());
3297 typeConverter.addConversion([&](OpenArrayType type) -> std::optional<Type> {
3298 return LLVM::LLVMPointerType::get(type.getContext());
3301 typeConverter.addConversion(
3302 [&](OpenUnpackedArrayType type) -> std::optional<Type> {
3303 return LLVM::LLVMPointerType::get(type.getContext());
3306 typeConverter.addConversion([&](StructType type) -> std::optional<Type> {
3307 SmallVector<hw::StructType::FieldInfo> fields;
3308 for (
auto field : type.getMembers()) {
3309 hw::StructType::FieldInfo info;
3310 info.type = typeConverter.convertType(field.type);
3313 info.name = field.name;
3314 fields.push_back(info);
3316 return hw::StructType::get(type.getContext(), fields);
3324 typeConverter.addConversion(
3325 [&](UnpackedStructType type) -> std::optional<Type> {
3326 SmallVector<hw::StructType::FieldInfo> fields;
3327 for (
auto field : type.getMembers()) {
3328 hw::StructType::FieldInfo info;
3329 info.type = typeConverter.convertType(field.type);
3332 info.name = field.name;
3333 fields.push_back(info);
3335 return hw::StructType::get(type.getContext(), fields);
3339 typeConverter.addConversion([&](UnionType type) -> std::optional<Type> {
3340 SmallVector<hw::UnionType::FieldInfo> fields;
3341 for (
auto field : type.getMembers()) {
3342 hw::UnionType::FieldInfo info;
3343 info.type = typeConverter.convertType(field.type);
3346 info.name = field.name;
3348 fields.push_back(info);
3350 auto result = hw::UnionType::get(type.getContext(), fields);
3355 typeConverter.addConversion(
3356 [&](UnpackedUnionType type) -> std::optional<Type> {
3357 SmallVector<hw::UnionType::FieldInfo> fields;
3358 for (
auto field : type.getMembers()) {
3359 hw::UnionType::FieldInfo info;
3360 info.type = typeConverter.convertType(field.type);
3363 info.name = field.name;
3365 fields.push_back(info);
3367 return hw::UnionType::get(type.getContext(), fields);
3371 typeConverter.addConversion([&](ChandleType type) -> std::optional<Type> {
3372 return LLVM::LLVMPointerType::get(type.getContext());
3376 typeConverter.addConversion(
3377 [](LLVM::LLVMPointerType t) -> std::optional<Type> {
return t; });
3380 typeConverter.addConversion([&](ClassHandleType type) -> std::optional<Type> {
3381 return LLVM::LLVMPointerType::get(type.getContext());
3384 typeConverter.addConversion([&](RefType type) -> std::optional<Type> {
3385 if (isa<OpenArrayType, OpenUnpackedArrayType>(type.getNestedType()))
3386 return LLVM::LLVMPointerType::get(type.getContext());
3387 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
3388 return llhd::RefType::get(innerType);
3393 typeConverter.addConversion([](IntegerType type) {
return type; });
3394 typeConverter.addConversion([](FloatType type) {
return type; });
3395 typeConverter.addConversion([](sim::DynamicStringType type) {
return type; });
3396 typeConverter.addConversion([](llhd::TimeType type) {
return type; });
3397 typeConverter.addConversion([](debug::ArrayType type) {
return type; });
3398 typeConverter.addConversion([](debug::ScopeType type) {
return type; });
3399 typeConverter.addConversion([](debug::StructType type) {
return type; });
3401 typeConverter.addConversion([&](llhd::RefType type) -> std::optional<Type> {
3402 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
3403 return llhd::RefType::get(innerType);
3407 typeConverter.addConversion([&](hw::ArrayType type) -> std::optional<Type> {
3408 if (
auto elementType = typeConverter.convertType(type.getElementType()))
3409 return hw::ArrayType::get(
elementType, type.getNumElements());
3413 typeConverter.addConversion([&](hw::StructType type) -> std::optional<Type> {
3414 SmallVector<hw::StructType::FieldInfo> fields;
3415 for (
auto field : type.getElements()) {
3416 hw::StructType::FieldInfo info;
3417 info.type = typeConverter.convertType(field.type);
3420 info.name = field.name;
3421 fields.push_back(info);
3423 return hw::StructType::get(type.getContext(), fields);
3426 typeConverter.addConversion([&](hw::UnionType type) -> std::optional<Type> {
3427 SmallVector<hw::UnionType::FieldInfo> fields;
3428 for (
auto field : type.getElements()) {
3429 hw::UnionType::FieldInfo info;
3430 info.type = typeConverter.convertType(field.type);
3433 info.name = field.name;
3434 info.offset = field.offset;
3435 fields.push_back(info);
3437 return hw::UnionType::get(type.getContext(), fields);
3440 typeConverter.addTargetMaterialization(
3441 [&](mlir::OpBuilder &builder, mlir::Type resultType,
3442 mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
3443 if (inputs.size() != 1 || !inputs[0])
3445 return UnrealizedConversionCastOp::create(builder, loc, resultType,
3450 typeConverter.addSourceMaterialization(
3451 [&](mlir::OpBuilder &builder, mlir::Type resultType,
3452 mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
3453 if (inputs.size() != 1)
3455 return UnrealizedConversionCastOp::create(builder, loc, resultType,
3462 TypeConverter &typeConverter,
3463 ClassTypeCache &classCache,
3464 FunctionCache &funcCache) {
3469 classCache, funcCache);
3470 patterns.add<ClassPropertyRefOpConversion>(typeConverter,
3471 patterns.getContext(), classCache);
3475 ClassUpcastOpConversion,
3477 VariableOpConversion,
3481 ConversionOpConversion,
3482 BitcastConversion<PackedToSBVOp>,
3483 BitcastConversion<SBVToPackedOp>,
3484 NoOpConversion<LogicToIntOp>,
3485 NoOpConversion<IntToLogicOp>,
3486 NoOpConversion<ToBuiltinIntOp>,
3487 NoOpConversion<FromBuiltinIntOp>,
3491 SIntToRealOpConversion,
3492 UIntToRealOpConversion,
3493 IntToStringOpConversion,
3494 RealToIntOpConversion,
3495 ConvertRealOpConversion,
3501 ReplicateOpConversion,
3503 ExtractOpConversion,
3504 DynExtractOpConversion,
3505 DynExtractRefOpConversion,
3507 StructExtractOpConversion,
3508 StructExtractRefOpConversion,
3509 ExtractRefOpConversion,
3510 StructCreateOpConversion,
3511 UnionCreateOpConversion,
3512 UnionExtractOpConversion,
3513 UnionExtractRefOpConversion,
3514 ConditionalOpConversion,
3515 ArrayCreateOpConversion,
3518 ConstantStringOpConv,
3521 ReduceAndOpConversion,
3522 ReduceOrOpConversion,
3523 ReduceXorOpConversion,
3524 BoolCastOpConversion,
3529 BinaryOpConversion<AddOp, comb::AddOp>,
3530 BinaryOpConversion<SubOp, comb::SubOp>,
3531 BinaryOpConversion<MulOp, comb::MulOp>,
3532 BinaryOpConversion<DivUOp, comb::DivUOp>,
3533 BinaryOpConversion<DivSOp, comb::DivSOp>,
3534 BinaryOpConversion<ModUOp, comb::ModUOp>,
3535 BinaryOpConversion<ModSOp, comb::ModSOp>,
3536 BinaryOpConversion<AndOp, comb::AndOp>,
3537 BinaryOpConversion<OrOp, comb::OrOp>,
3538 BinaryOpConversion<XorOp, comb::XorOp>,
3541 NegRealOpConversion,
3544 BinaryRealOpConversion<AddRealOp, arith::AddFOp>,
3545 BinaryRealOpConversion<SubRealOp, arith::SubFOp>,
3546 BinaryRealOpConversion<DivRealOp, arith::DivFOp>,
3547 BinaryRealOpConversion<MulRealOp, arith::MulFOp>,
3548 BinaryRealOpConversion<PowRealOp, math::PowFOp>,
3551 PowUOpConversion, PowSOpConversion,
3554 ICmpOpConversion<UltOp, ICmpPredicate::ult>,
3555 ICmpOpConversion<SltOp, ICmpPredicate::slt>,
3556 ICmpOpConversion<UleOp, ICmpPredicate::ule>,
3557 ICmpOpConversion<SleOp, ICmpPredicate::sle>,
3558 ICmpOpConversion<UgtOp, ICmpPredicate::ugt>,
3559 ICmpOpConversion<SgtOp, ICmpPredicate::sgt>,
3560 ICmpOpConversion<UgeOp, ICmpPredicate::uge>,
3561 ICmpOpConversion<SgeOp, ICmpPredicate::sge>,
3562 ICmpOpConversion<EqOp, ICmpPredicate::eq>,
3563 ICmpOpConversion<NeOp, ICmpPredicate::ne>,
3564 ICmpOpConversion<CaseEqOp, ICmpPredicate::ceq>,
3565 ICmpOpConversion<CaseNeOp, ICmpPredicate::cne>,
3566 ICmpOpConversion<WildcardEqOp, ICmpPredicate::weq>,
3567 ICmpOpConversion<WildcardNeOp, ICmpPredicate::wne>,
3568 FCmpOpConversion<NeRealOp, arith::CmpFPredicate::ONE>,
3569 FCmpOpConversion<FltOp, arith::CmpFPredicate::OLT>,
3570 FCmpOpConversion<FleOp, arith::CmpFPredicate::OLE>,
3571 FCmpOpConversion<FgtOp, arith::CmpFPredicate::OGT>,
3572 FCmpOpConversion<FgeOp, arith::CmpFPredicate::OGE>,
3573 FCmpOpConversion<EqRealOp, arith::CmpFPredicate::OEQ>,
3574 CaseXZEqOpConversion<CaseZEqOp, true>,
3575 CaseXZEqOpConversion<CaseXZEqOp, false>,
3578 SVModuleOpConversion,
3579 InstanceOpConversion,
3580 ProcedureOpConversion,
3581 CoroutineOpConversion,
3582 CallCoroutineOpConversion,
3583 WaitEventOpConversion,
3591 AssignOpConversion<ContinuousAssignOp>,
3592 AssignOpConversion<DelayedContinuousAssignOp>,
3593 AssignOpConversion<BlockingAssignOp>,
3594 AssignOpConversion<NonBlockingAssignOp>,
3595 AssignOpConversion<DelayedNonBlockingAssignOp>,
3596 AssignedVariableOpConversion,
3599 HWInstanceOpConversion,
3602 DPIFuncOpConversion,
3603 FuncDPICallOpConversion,
3604 UnrealizedConversionCastConversion,
3605 InPlaceOpConversion<debug::ArrayOp>,
3606 InPlaceOpConversion<debug::StructOp>,
3607 InPlaceOpConversion<debug::VariableOp>,
3610 AssertLikeOpConversion<AssertOp, verif::AssertOp>,
3611 AssertLikeOpConversion<AssumeOp, verif::AssumeOp>,
3612 AssertLikeOpConversion<CoverOp, verif::CoverOp>,
3615 FormatLiteralOpConversion,
3616 FormatStringOpConversion,
3617 FormatConcatOpConversion,
3618 FormatHierPathOpConversion,
3619 FormatIntOpConversion,
3620 FormatRealOpConversion,
3621 FormatCharOpConversion,
3622 DisplayBIOpConversion,
3623 FDisplayBIOpConversion,
3626 FOpenBIOpConversion,
3627 FCloseBIOpConversion,
3628 FFlushBIOpConversion,
3631 PlusArgsTestBIOpConversion,
3632 PlusArgsValueBIOpConversion,
3635 StringLenOpConversion,
3636 StringConcatOpConversion,
3637 StringGetOpConversion,
3640 QueueSizeBIOpConversion,
3641 QueuePushBackOpConversion,
3642 QueuePushFrontOpConversion,
3643 QueuePopBackOpConversion,
3644 QueuePopFrontOpConversion,
3645 QueueDeleteOpConversion,
3646 QueueInsertOpConversion,
3647 QueueClearOpConversion,
3648 DynQueueExtractOpConversion,
3649 QueueResizeOpConversion,
3650 QueueSetOpConversion,
3651 QueueCmpOpConversion,
3652 QueueFromUnpackedArrayOpConversion,
3653 QueueConcatOpConversion
3654 >(typeConverter,
patterns.getContext());
3677 mlir::populateAnyFunctionOpInterfaceTypeConversionPattern(
patterns,
3679 hw::populateHWModuleLikeTypeConversionPattern(
3680 hw::HWModuleOp::getOperationName(),
patterns, typeConverter);
3681 populateSCFToControlFlowConversionPatterns(
patterns);
3690struct MooreToCorePass
3691 :
public circt::impl::ConvertMooreToCoreBase<MooreToCorePass> {
3692 void runOnOperation()
override;
3698 return std::make_unique<MooreToCorePass>();
3702void MooreToCorePass::runOnOperation() {
3703 MLIRContext &
context = getContext();
3704 ModuleOp
module = getOperation();
3705 ClassTypeCache classCache;
3706 auto &symbolTable = getAnalysis<SymbolTable>();
3707 FunctionCache funcCache(symbolTable);
3709 IRRewriter rewriter(module);
3710 (void)mlir::eraseUnreachableBlocks(rewriter, module->getRegions());
3712 TypeConverter typeConverter;
3715 ConversionTarget target(
context);
3720 mlir::cf::populateCFStructuralTypeConversionsAndLegality(typeConverter,
3723 if (failed(applyFullConversion(module, target, std::move(
patterns))))
3724 signalPassFailure();
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static FIRRTLBaseType convertType(FIRRTLBaseType type)
Returns null type if no conversion is needed.
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 populateOpConversion(ConversionPatternSet &patterns, TypeConverter &typeConverter, ClassTypeCache &classCache, FunctionCache &funcCache)
static void populateLegality(ConversionTarget &target, const TypeConverter &converter)
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.