22#include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h"
23#include "mlir/Dialect/Arith/IR/Arith.h"
24#include "mlir/Dialect/Arith/IR/ArithAttributes.h"
25#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
26#include "mlir/Dialect/ControlFlow/Transforms/StructuralTypeConversions.h"
27#include "mlir/Dialect/Func/IR/FuncOps.h"
28#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
29#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
30#include "mlir/Dialect/Math/IR/Math.h"
31#include "mlir/Dialect/SCF/IR/SCF.h"
32#include "mlir/Dialect/UB/IR/UBOps.h"
33#include "mlir/IR/BuiltinDialect.h"
34#include "mlir/IR/Iterators.h"
35#include "mlir/Interfaces/SideEffectInterfaces.h"
36#include "mlir/Pass/Pass.h"
37#include "mlir/Transforms/DialectConversion.h"
38#include "mlir/Transforms/RegionUtils.h"
39#include "llvm/ADT/TypeSwitch.h"
40#include "llvm/IR/DerivedTypes.h"
43#define GEN_PASS_DEF_CONVERTMOORETOCORE
44#include "circt/Conversion/Passes.h.inc"
51using comb::ICmpPredicate;
52using llvm::SmallDenseSet;
57struct ClassTypeCache {
59 LLVM::GlobalOp global;
62 struct ClassStructInfo {
63 LLVM::LLVMStructType classBody;
64 LLVM::LLVMStructType headerTy;
65 TypeInfoInfo typeInfo;
67 unsigned headerFieldIndex = 0;
68 unsigned typeInfoFieldIndex = 0;
69 unsigned vtableFieldIndex = 1;
72 DenseMap<StringRef, SmallVector<unsigned, 2>> propertyPath;
76 void setFieldPath(StringRef propertyName, ArrayRef<unsigned> path) {
77 this->propertyPath[propertyName] =
78 SmallVector<unsigned, 2>(path.begin(), path.end());
82 std::optional<ArrayRef<unsigned>>
83 getFieldPath(StringRef propertySym)
const {
84 if (
auto prop = this->propertyPath.find(propertySym);
85 prop != this->propertyPath.end())
86 return ArrayRef<unsigned>(prop->second);
93 void setClassInfo(SymbolRefAttr classSym,
const ClassStructInfo &
info) {
94 auto &dst = classToStructMap[classSym];
99 std::optional<ClassStructInfo> getStructInfo(SymbolRefAttr classSym)
const {
100 if (
auto it = classToStructMap.find(classSym); it != classToStructMap.end())
105 std::optional<TypeInfoInfo> getTypeInfo(SymbolRefAttr classSym)
const {
106 if (
auto it = classToTypeInfoMap.find(classSym);
107 it != classToTypeInfoMap.end())
112 void setTypeInfo(SymbolRefAttr classSym,
const TypeInfoInfo &
info) {
113 classToTypeInfoMap[classSym] =
info;
120 DenseMap<Attribute, ClassStructInfo> classToStructMap;
121 DenseMap<Attribute, TypeInfoInfo> classToTypeInfoMap;
126struct FunctionCache {
127 FunctionCache(SymbolTable &symbolTable) : symbolTable(symbolTable) {}
133 func::FuncOp getOrCreate(OpBuilder &builder, StringRef name,
134 function_ref<func::FuncOp()> createFn) {
135 auto &slot = map[name];
138 if (
auto fn = symbolTable.lookup<func::FuncOp>(name))
140 auto mod = cast<ModuleOp>(symbolTable.getOp());
141 OpBuilder::InsertionGuard g(builder);
142 builder.setInsertionPointToStart(mod.getBody());
144 symbolTable.insert(slot);
150 func::FuncOp getOrCreate(OpBuilder &builder, StringRef name,
151 TypeRange argTypes, TypeRange resultTypes) {
152 return getOrCreate(builder, name, [&] {
153 auto mod = cast<ModuleOp>(symbolTable.getOp());
154 auto fnTy = builder.getFunctionType(argTypes, resultTypes);
155 auto fn = func::FuncOp::create(builder, mod.getLoc(), name, fnTy);
162 SymbolTable &symbolTable;
163 llvm::StringMap<func::FuncOp> map;
168static LLVM::LLVMStructType getOrCreateOpaqueStruct(MLIRContext *ctx,
169 SymbolRefAttr className) {
170 return LLVM::LLVMStructType::getIdentified(ctx, className.getRootReference());
174static LLVM::LLVMStructType getClassObjectHeaderType(MLIRContext *ctx) {
175 return LLVM::LLVMStructType::getLiteral(
176 ctx, SmallVector<Type>{LLVM::LLVMPointerType::get(ctx),
177 LLVM::LLVMPointerType::get(ctx)});
180static std::string getTypeInfoName(SymbolRefAttr className) {
181 return className.getRootReference().str() +
"::typeinfo";
184static FailureOr<ClassTypeCache::TypeInfoInfo>
185getOrCreateTypeInfo(ModuleOp mod, SymbolRefAttr classSym,
186 ClassTypeCache &cache) {
187 if (
auto info = cache.getTypeInfo(classSym))
190 MLIRContext *ctx = mod.getContext();
191 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
192 auto typeInfoTy = LLVM::LLVMStructType::getLiteral(ctx, {ptrTy});
194 auto globalName = getTypeInfoName(classSym);
195 auto global = mod.lookupSymbol<LLVM::GlobalOp>(globalName);
197 OpBuilder builder = OpBuilder::atBlockBegin(mod.getBody());
198 global = LLVM::GlobalOp::create(
199 builder, mod.getLoc(), typeInfoTy,
200 true, LLVM::Linkage::Internal, globalName, Attribute());
203 global.getInitializerRegion().push_back(block);
204 builder.setInsertionPointToStart(block);
206 if (
auto *classOp = mod.lookupSymbol(classSym)) {
207 auto classDecl = dyn_cast<ClassDeclOp>(classOp);
208 if (classDecl && classDecl.getBaseAttr()) {
210 getOrCreateTypeInfo(mod, classDecl.getBaseAttr(), cache);
211 if (failed(baseInfo))
214 LLVM::AddressOfOp::create(builder, mod.getLoc(), baseInfo->global);
215 auto undef = LLVM::UndefOp::create(builder, mod.getLoc(), typeInfoTy)
217 auto init = LLVM::InsertValueOp::create(builder, mod.getLoc(), undef,
218 baseAddr.getResult(),
219 ArrayRef<int64_t>{0});
220 LLVM::ReturnOp::create(builder, mod.getLoc(), init);
221 ClassTypeCache::TypeInfoInfo
info{global};
222 cache.setTypeInfo(classSym, info);
228 LLVM::UndefOp::create(builder, mod.getLoc(), typeInfoTy).getResult();
230 LLVM::ZeroOp::create(builder, mod.getLoc(), ptrTy).getResult();
231 auto init = LLVM::InsertValueOp::create(builder, mod.getLoc(), undef,
232 nullPtr, ArrayRef<int64_t>{0});
233 LLVM::ReturnOp::create(builder, mod.getLoc(), init);
236 ClassTypeCache::TypeInfoInfo
info{global};
237 cache.setTypeInfo(classSym, info);
240static LogicalResult resolveClassStructBody(ClassDeclOp op,
241 TypeConverter
const &typeConverter,
242 ClassTypeCache &cache) {
244 auto classSym = SymbolRefAttr::get(op.getSymNameAttr());
245 auto structInfo = cache.getStructInfo(classSym);
250 if (failed(getOrCreateTypeInfo(op->getParentOfType<ModuleOp>(), classSym,
252 return op.emitOpError() <<
"Failed to create RTTI for class";
255 ClassTypeCache::ClassStructInfo structBody;
256 SmallVector<Type> structBodyMembers;
257 structBody.headerTy = getClassObjectHeaderType(op.getContext());
258 structBody.typeInfo = *cache.getTypeInfo(classSym);
259 structBodyMembers.push_back(structBody.headerTy);
262 unsigned derivedStartIdx = 1;
264 if (
auto baseClass = op.getBaseAttr()) {
266 ModuleOp mod = op->getParentOfType<ModuleOp>();
267 auto *opSym = mod.lookupSymbol(baseClass);
268 auto classDeclOp = cast<ClassDeclOp>(opSym);
270 if (failed(resolveClassStructBody(classDeclOp, typeConverter, cache)))
274 auto baseClassStruct = cache.getStructInfo(baseClass);
275 structBodyMembers.push_back(baseClassStruct->classBody);
280 for (
auto &kv : baseClassStruct->propertyPath) {
281 SmallVector<unsigned, 2> path;
283 path.append(kv.second.begin(), kv.second.end());
284 structBody.setFieldPath(kv.first, path);
289 unsigned iterator = derivedStartIdx;
290 auto &block = op.getBody().front();
291 for (Operation &child : block) {
292 if (
auto prop = dyn_cast<ClassPropertyDeclOp>(child)) {
293 Type mooreTy = prop.getPropertyType();
294 Type llvmTy = typeConverter.convertType(mooreTy);
296 return prop.emitOpError()
297 <<
"failed to convert property type " << mooreTy;
299 structBodyMembers.push_back(llvmTy);
302 SmallVector<unsigned, 2> path{iterator};
303 structBody.setFieldPath(prop.getSymName(), path);
309 auto llvmStructTy = getOrCreateOpaqueStruct(op.getContext(), classSym);
311 if (!structBodyMembers.empty() &&
312 failed(llvmStructTy.setBody(structBodyMembers,
false)))
313 return op.emitOpError() <<
"Failed to set LLVM Struct body";
315 structBody.classBody = llvmStructTy;
316 cache.setClassInfo(classSym, structBody);
322static LogicalResult resolveClassStructBody(ModuleOp mod, SymbolRefAttr op,
323 TypeConverter
const &typeConverter,
324 ClassTypeCache &cache) {
325 auto classDeclOp = cast<ClassDeclOp>(*mod.lookupSymbol(op));
326 return resolveClassStructBody(classDeclOp, typeConverter, cache);
333static Value adjustIntegerWidth(OpBuilder &builder, Value value,
334 uint32_t targetWidth, Location loc) {
335 uint32_t intWidth = value.getType().getIntOrFloatBitWidth();
336 if (intWidth == targetWidth)
339 if (intWidth < targetWidth) {
341 builder, loc, builder.getIntegerType(targetWidth - intWidth), 0);
342 return comb::ConcatOp::create(builder, loc, ValueRange{zeroExt, value});
346 intWidth - targetWidth);
348 builder, loc, builder.getIntegerType(intWidth - targetWidth), 0);
349 Value isZero = comb::ICmpOp::create(builder, loc, comb::ICmpPredicate::eq, hi,
353 builder.getIntegerType(targetWidth), -1);
354 return comb::MuxOp::create(builder, loc, isZero, lo, max,
false);
358static FailureOr<hw::ModulePortInfo>
359getModulePortInfo(
const TypeConverter &typeConverter, SVModuleOp op) {
361 size_t resultNum = 0;
362 auto moduleTy = op.getModuleType();
363 SmallVector<hw::PortInfo> ports;
364 ports.reserve(moduleTy.getNumPorts());
366 for (
auto port : moduleTy.getPorts()) {
367 Type portTy = typeConverter.convertType(port.type);
369 return op.emitOpError(
"port '")
370 << port.name <<
"' has unsupported type " << port.type
371 <<
" that cannot be converted to hardware type";
375 hw::PortInfo({{port.name, portTy, port.dir}, resultNum++, {}}));
383 hw::PortInfo({{port.name, portTy, port.dir}, inputNum++, {}}));
394 using OpConversionPattern::OpConversionPattern;
397 matchAndRewrite(SVModuleOp op, OpAdaptor adaptor,
398 ConversionPatternRewriter &rewriter)
const override {
399 rewriter.setInsertionPoint(op);
402 auto portInfo = getModulePortInfo(*typeConverter, op);
403 if (failed(portInfo))
406 auto hwModuleOp = hw::HWModuleOp::create(rewriter, op.getLoc(),
407 op.getSymNameAttr(), *portInfo);
408 if (
auto svAttrs = sv::getSVAttributes(op))
409 sv::setSVAttributes(hwModuleOp, svAttrs);
412 SymbolTable::setSymbolVisibility(hwModuleOp,
413 SymbolTable::getSymbolVisibility(op));
414 rewriter.eraseBlock(hwModuleOp.getBodyBlock());
416 rewriter.convertRegionTypes(&op.getBodyRegion(), *typeConverter)))
418 rewriter.inlineRegionBefore(op.getBodyRegion(), hwModuleOp.getBodyRegion(),
419 hwModuleOp.getBodyRegion().end());
422 rewriter.eraseOp(op);
428 using OpConversionPattern::OpConversionPattern;
431 matchAndRewrite(OutputOp op, OpAdaptor adaptor,
432 ConversionPatternRewriter &rewriter)
const override {
433 rewriter.replaceOpWithNewOp<hw::OutputOp>(op, adaptor.getOperands());
439 using OpConversionPattern::OpConversionPattern;
442 matchAndRewrite(InstanceOp op, OpAdaptor adaptor,
443 ConversionPatternRewriter &rewriter)
const override {
444 auto instName = op.getInstanceNameAttr();
445 auto moduleName = op.getModuleNameAttr();
448 rewriter.setInsertionPoint(op);
449 auto instOp = hw::InstanceOp::create(
450 rewriter, op.getLoc(), op.getResultTypes(), instName, moduleName,
451 op.getInputs(), op.getInputNamesAttr(), op.getOutputNamesAttr(),
452 rewriter.getArrayAttr({}),
nullptr,
456 op.replaceAllUsesWith(instOp.getResults());
457 rewriter.eraseOp(op);
463static void setInsertionPointAfterDef(OpBuilder &rewriter, Value value) {
464 if (
auto *defOp = value.getDefiningOp())
465 rewriter.setInsertionPointAfter(defOp);
466 if (isa<BlockArgument>(value))
467 rewriter.setInsertionPointToStart(value.getParentBlock());
470static void getValuesToObserve(Region *region,
471 function_ref<
void(Value)> setInsertionPoint,
472 const TypeConverter *typeConverter,
473 ConversionPatternRewriter &rewriter,
474 SmallVector<Value> &observeValues) {
475 SmallDenseSet<Value> alreadyObserved;
476 Location loc = region->getLoc();
478 auto probeIfSignal = [&](Value value) -> Value {
479 Type type = value.getType();
480 if (
auto refType = dyn_cast<llhd::RefType>(type)) {
483 return llhd::ProbeOp::create(rewriter, loc, value);
490 region->getParentOp()->walk<WalkOrder::PreOrder, ForwardDominanceIterator<>>(
491 [&](Operation *operation) {
492 for (
auto value : operation->getOperands()) {
493 if (isa<BlockArgument>(value))
494 value = rewriter.getRemappedValue(value);
496 if (region->isAncestor(value.getParentRegion()))
498 if (
auto *defOp = value.getDefiningOp();
499 defOp && defOp->hasTrait<OpTrait::ConstantLike>())
501 if (!alreadyObserved.insert(value).second)
504 OpBuilder::InsertionGuard g(rewriter);
505 if (
auto remapped = rewriter.getRemappedValue(value)) {
506 setInsertionPoint(remapped);
507 if (
auto observed = probeIfSignal(remapped))
508 observeValues.push_back(observed);
510 setInsertionPoint(value);
511 auto type = typeConverter->convertType(value.getType());
512 auto converted = typeConverter->materializeTargetConversion(
513 rewriter, loc, type, value);
514 if (
auto observed = probeIfSignal(converted))
515 observeValues.push_back(observed);
522 using OpConversionPattern::OpConversionPattern;
525 matchAndRewrite(ProcedureOp op, OpAdaptor adaptor,
526 ConversionPatternRewriter &rewriter)
const override {
528 SmallVector<Value> observedValues;
529 if (op.getKind() == ProcedureKind::AlwaysComb ||
530 op.getKind() == ProcedureKind::AlwaysLatch) {
531 auto setInsertionPoint = [&](Value value) {
532 rewriter.setInsertionPoint(op);
534 getValuesToObserve(&op.getBody(), setInsertionPoint, typeConverter,
535 rewriter, observedValues);
538 auto loc = op.getLoc();
539 if (failed(rewriter.convertRegionTypes(&op.getBody(), *typeConverter)))
544 if (op.getKind() == ProcedureKind::Initial ||
545 op.getKind() == ProcedureKind::Final) {
547 if (op.getKind() == ProcedureKind::Initial)
548 newOp = llhd::ProcessOp::create(rewriter, loc, TypeRange{});
550 newOp = llhd::FinalOp::create(rewriter, loc);
551 auto &body = newOp->getRegion(0);
552 rewriter.inlineRegionBefore(op.getBody(), body, body.end());
554 llvm::make_early_inc_range(body.getOps<ReturnOp>())) {
555 rewriter.setInsertionPoint(returnOp);
556 rewriter.replaceOpWithNewOp<llhd::HaltOp>(returnOp, ValueRange{});
558 rewriter.eraseOp(op);
563 auto newOp = llhd::ProcessOp::create(rewriter, loc, TypeRange{});
568 rewriter.createBlock(&newOp.getBody());
569 auto *block = &op.getBody().front();
570 cf::BranchOp::create(rewriter, loc, block);
571 rewriter.inlineRegionBefore(op.getBody(), newOp.getBody(),
572 newOp.getBody().end());
580 if (op.getKind() == ProcedureKind::AlwaysComb ||
581 op.getKind() == ProcedureKind::AlwaysLatch) {
582 Block *waitBlock = rewriter.createBlock(&newOp.getBody());
583 llhd::WaitOp::create(rewriter, loc, ValueRange{}, Value(), observedValues,
584 ValueRange{}, block);
591 for (
auto returnOp : llvm::make_early_inc_range(newOp.getOps<ReturnOp>())) {
592 rewriter.setInsertionPoint(returnOp);
593 cf::BranchOp::create(rewriter, loc, block);
594 rewriter.eraseOp(returnOp);
597 rewriter.eraseOp(op);
607 using OpConversionPattern::OpConversionPattern;
610 matchAndRewrite(CoroutineOp op, OpAdaptor adaptor,
611 ConversionPatternRewriter &rewriter)
const override {
612 auto funcType = op.getFunctionType();
613 TypeConverter::SignatureConversion sigConversion(funcType.getNumInputs());
614 for (
auto [i, type] : llvm::enumerate(funcType.getInputs())) {
615 auto converted = typeConverter->convertType(type);
618 sigConversion.addInputs(i, converted);
620 SmallVector<Type> resultTypes;
621 if (failed(typeConverter->convertTypes(funcType.getResults(), resultTypes)))
624 auto newFuncType = FunctionType::get(
625 rewriter.getContext(), sigConversion.getConvertedTypes(), resultTypes);
626 auto newOp = llhd::CoroutineOp::create(rewriter, op.getLoc(),
627 op.getSymName(), newFuncType);
628 newOp.setSymVisibilityAttr(op.getSymVisibilityAttr());
629 if (
auto dpiExport = op->getAttr(
"circt.dpi.export"))
630 newOp->setAttr(
"circt.dpi.export", dpiExport);
631 rewriter.inlineRegionBefore(op.getBody(), newOp.getBody(),
632 newOp.getBody().end());
633 if (failed(rewriter.convertRegionTypes(&newOp.getBody(), *typeConverter,
639 llvm::make_early_inc_range(newOp.getBody().getOps<ReturnOp>())) {
640 rewriter.setInsertionPoint(returnOp);
641 rewriter.replaceOpWithNewOp<llhd::ReturnOp>(returnOp, ValueRange{});
644 rewriter.eraseOp(op);
650 using OpConversionPattern::OpConversionPattern;
653 matchAndRewrite(CallCoroutineOp op, OpAdaptor adaptor,
654 ConversionPatternRewriter &rewriter)
const override {
655 SmallVector<Type> convResTypes;
656 if (failed(typeConverter->convertTypes(op.getResultTypes(), convResTypes)))
658 rewriter.replaceOpWithNewOp<llhd::CallCoroutineOp>(
659 op, convResTypes, adaptor.getCallee(), adaptor.getOperands());
665 using OpConversionPattern::OpConversionPattern;
668 matchAndRewrite(WaitEventOp op, OpAdaptor adaptor,
669 ConversionPatternRewriter &rewriter)
const override {
703 rewriter.splitBlock(op->getBlock(), ++Block::iterator(op));
709 SmallVector<DetectEventOp> detectOps(op.getBody().getOps<DetectEventOp>());
710 if (detectOps.empty()) {
713 rewriter.replaceOpWithNewOp<llhd::HaltOp>(op, ValueRange{});
717 auto *waitBlock = rewriter.createBlock(resumeBlock);
718 auto *checkBlock = rewriter.createBlock(resumeBlock);
720 auto loc = op.getLoc();
721 rewriter.setInsertionPoint(op);
722 cf::BranchOp::create(rewriter, loc, waitBlock);
732 SmallVector<Value> valuesBefore;
733 rewriter.setInsertionPointToEnd(waitBlock);
734 auto clonedOp = cast<WaitEventOp>(rewriter.clone(*op));
735 bool allDetectsAreAnyChange =
true;
737 llvm::make_early_inc_range(clonedOp.getOps<DetectEventOp>())) {
738 if (detectOp.getEdge() != Edge::AnyChange || detectOp.getCondition())
739 allDetectsAreAnyChange =
false;
740 valuesBefore.push_back(detectOp.getInput());
741 rewriter.eraseOp(detectOp);
747 SmallVector<Value> observeValues;
750 [&](Value value) { setInsertionPointAfterDef(rewriter, value); },
751 typeConverter, rewriter, observeValues);
756 auto waitOp = llhd::WaitOp::create(rewriter, loc, ValueRange{}, Value(),
757 observeValues, ValueRange{}, checkBlock);
758 rewriter.inlineBlockBefore(&clonedOp.getBody().front(), waitOp);
759 rewriter.eraseOp(clonedOp);
762 rewriter.inlineBlockBefore(&op.getBody().front(), checkBlock,
764 rewriter.eraseOp(op);
768 auto computeTrigger = [&](Value before, Value after, Edge edge) -> Value {
769 assert(before.getType() == after.getType() &&
770 "mismatched types after clone op");
771 auto beforeType = cast<IntType>(before.getType());
775 if (beforeType.getWidth() != 1 && edge != Edge::AnyChange) {
776 constexpr int LSB = 0;
778 IntType::get(rewriter.getContext(), 1, beforeType.getDomain());
780 moore::ExtractOp::create(rewriter, loc, beforeType, before, LSB);
781 after = moore::ExtractOp::create(rewriter, loc, beforeType, after, LSB);
784 auto intType = rewriter.getIntegerType(beforeType.getWidth());
785 before = typeConverter->materializeTargetConversion(rewriter, loc,
787 after = typeConverter->materializeTargetConversion(rewriter, loc, intType,
790 if (edge == Edge::AnyChange)
791 return comb::ICmpOp::create(rewriter, loc, ICmpPredicate::ne, before,
794 SmallVector<Value> disjuncts;
797 if (edge == Edge::PosEdge || edge == Edge::BothEdges) {
799 comb::XorOp::create(rewriter, loc, before, trueVal,
true);
801 comb::AndOp::create(rewriter, loc, notOldVal, after,
true);
802 disjuncts.push_back(posedge);
805 if (edge == Edge::NegEdge || edge == Edge::BothEdges) {
807 comb::XorOp::create(rewriter, loc, after, trueVal,
true);
809 comb::AndOp::create(rewriter, loc, before, notCurrVal,
true);
810 disjuncts.push_back(posedge);
813 return rewriter.createOrFold<comb::OrOp>(loc, disjuncts,
true);
820 SmallVector<Value> triggers;
821 for (
auto [detectOp, before] : llvm::zip(detectOps, valuesBefore)) {
822 if (!allDetectsAreAnyChange) {
823 if (!isa<IntType>(before.getType()))
824 return detectOp->emitError() <<
"requires int operand";
826 rewriter.setInsertionPoint(detectOp);
828 computeTrigger(before, detectOp.getInput(), detectOp.getEdge());
829 if (detectOp.getCondition()) {
830 auto condition = typeConverter->materializeTargetConversion(
831 rewriter, loc, rewriter.getI1Type(), detectOp.getCondition());
833 comb::AndOp::create(rewriter, loc, trigger, condition,
true);
835 triggers.push_back(trigger);
838 rewriter.eraseOp(detectOp);
841 rewriter.setInsertionPointToEnd(checkBlock);
842 if (triggers.empty()) {
847 cf::BranchOp::create(rewriter, loc, resumeBlock);
853 auto triggered = rewriter.createOrFold<comb::OrOp>(loc, triggers,
true);
854 cf::CondBranchOp::create(rewriter, loc, triggered, resumeBlock,
863 using OpConversionPattern::OpConversionPattern;
866 matchAndRewrite(WaitLevelOp op, OpAdaptor adaptor,
867 ConversionPatternRewriter &rewriter)
const override {
899 auto loc = op.getLoc();
900 auto detectOps = llvm::to_vector(op.getBody().getOps<DetectLevelOp>());
905 rewriter.splitBlock(op->getBlock(), ++Block::iterator(op));
906 if (detectOps.empty()) {
909 rewriter.replaceOpWithNewOp<llhd::HaltOp>(op, ValueRange{});
914 SmallVector<Value> observeValues;
917 [&](Value value) { setInsertionPointAfterDef(rewriter, value); },
918 typeConverter, rewriter, observeValues);
920 auto *waitBlock = rewriter.createBlock(resumeBlock);
921 auto *checkBlock = rewriter.createBlock(waitBlock);
923 rewriter.setInsertionPoint(op);
924 cf::BranchOp::create(rewriter, loc, checkBlock);
926 rewriter.setInsertionPointToEnd(waitBlock);
927 llhd::WaitOp::create(rewriter, loc, ValueRange{}, Value(), observeValues,
928 ValueRange{}, checkBlock);
930 rewriter.inlineBlockBefore(&op.getBody().front(), checkBlock,
932 rewriter.eraseOp(op);
936 SmallVector<Value> conditions;
937 for (
auto detectOp : detectOps) {
938 rewriter.setInsertionPoint(detectOp);
939 auto condition = typeConverter->materializeTargetConversion(
940 rewriter, loc, rewriter.getI1Type(), detectOp.getCondition());
942 return detectOp->emitError() <<
"cannot convert condition to i1";
943 conditions.push_back(condition);
944 rewriter.eraseOp(detectOp);
947 rewriter.setInsertionPointToEnd(checkBlock);
948 auto triggered = rewriter.createOrFold<comb::OrOp>(loc, conditions,
true);
949 cf::CondBranchOp::create(rewriter, loc, triggered, resumeBlock, waitBlock);
955static LogicalResult
convert(WaitDelayOp op, WaitDelayOp::Adaptor adaptor,
956 ConversionPatternRewriter &rewriter) {
958 rewriter.splitBlock(op->getBlock(), ++Block::iterator(op));
959 rewriter.setInsertionPoint(op);
960 rewriter.replaceOpWithNewOp<llhd::WaitOp>(op, ValueRange{},
961 adaptor.getDelay(), ValueRange{},
962 ValueRange{}, resumeBlock);
963 rewriter.setInsertionPointToStart(resumeBlock);
968static LogicalResult
convert(UnreachableOp op, UnreachableOp::Adaptor adaptor,
969 ConversionPatternRewriter &rewriter) {
970 rewriter.replaceOpWithNewOp<ub::UnreachableOp>(op);
979 ConversionPatternRewriter &rewriter) {
981 if (isa<mlir::LLVM::LLVMPointerType>(type))
982 return mlir::LLVM::ZeroOp::create(rewriter, loc, type);
985 if (isa<llhd::TimeType>(type)) {
987 llhd::TimeAttr::get(type.getContext(), 0U, llvm::StringRef(
"ns"), 0);
988 return llhd::ConstantTimeOp::create(rewriter, loc, timeAttr);
992 if (
auto floatType = dyn_cast<FloatType>(type)) {
993 auto floatAttr = rewriter.getFloatAttr(floatType, 0.0);
994 return mlir::arith::ConstantOp::create(rewriter, loc, floatAttr);
998 if (
auto strType = dyn_cast<sim::DynamicStringType>(type))
999 return sim::StringConstantOp::create(rewriter, loc, strType,
"");
1002 if (
auto assocArrayType = dyn_cast<sim::AssocArrayType>(type))
1003 return sim::AssocArrayEmptyOp::create(rewriter, loc, assocArrayType);
1006 if (
auto queueType = dyn_cast<sim::QueueType>(type))
1007 return sim::QueueEmptyOp::create(rewriter, loc, queueType);
1010 if (
auto arrayType = dyn_cast<hw::ArrayType>(type)) {
1016 SmallVector<Value> elements(arrayType.getNumElements(), zeroElement);
1021 if (
auto structType = dyn_cast<hw::StructType>(type)) {
1023 SmallVector<Value> fields;
1024 for (
auto field : structType.getElements()) {
1028 fields.push_back(zeroField);
1043 return rewriter.createOrFold<
hw::BitcastOp>(loc, type, constZero);
1046struct ClassPropertyRefOpConversion
1048 ClassPropertyRefOpConversion(TypeConverter &tc, MLIRContext *ctx,
1049 ClassTypeCache &cache)
1050 : OpConversionPattern(tc, ctx), cache(cache) {}
1053 matchAndRewrite(circt::moore::ClassPropertyRefOp op, OpAdaptor adaptor,
1054 ConversionPatternRewriter &rewriter)
const override {
1055 Location loc = op.getLoc();
1056 MLIRContext *ctx = rewriter.getContext();
1059 Type dstTy = getTypeConverter()->convertType(op.getPropertyRef().getType());
1061 Value instRef = adaptor.getInstance();
1065 cast<circt::moore::ClassHandleType>(op.getInstance().getType());
1066 SymbolRefAttr classSym = classRefTy.getClassSym();
1067 ModuleOp mod = op->getParentOfType<ModuleOp>();
1068 if (failed(resolveClassStructBody(mod, classSym, *typeConverter, cache)))
1069 return rewriter.notifyMatchFailure(op,
1070 "Could not resolve class struct for " +
1071 classSym.getRootReference().str());
1073 auto structInfo = cache.getStructInfo(classSym);
1074 assert(structInfo &&
"class struct info must exist");
1075 auto structTy = structInfo->classBody;
1078 auto propSym = op.getProperty();
1079 auto pathOpt = structInfo->getFieldPath(propSym);
1081 return rewriter.notifyMatchFailure(op,
1082 "no GEP path for property " + propSym);
1084 auto i32Ty = IntegerType::get(ctx, 32);
1085 SmallVector<Value> idxVals;
1086 for (
unsigned idx : *pathOpt)
1087 idxVals.push_back(LLVM::ConstantOp::create(
1088 rewriter, loc, i32Ty, rewriter.getI32IntegerAttr(idx)));
1091 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
1093 LLVM::GEPOp::create(rewriter, loc, ptrTy, structTy, instRef, idxVals);
1096 Value fieldRef = UnrealizedConversionCastOp::create(rewriter, loc, dstTy,
1100 rewriter.replaceOp(op, fieldRef);
1105 ClassTypeCache &cache;
1109 using OpConversionPattern::OpConversionPattern;
1112 matchAndRewrite(ClassUpcastOp op, OpAdaptor adaptor,
1113 ConversionPatternRewriter &rewriter)
const override {
1115 Type dstTy = getTypeConverter()->convertType(op.getResult().getType());
1116 Type srcTy = adaptor.getInstance().getType();
1119 return rewriter.notifyMatchFailure(op,
"failed to convert result type");
1122 if (dstTy == srcTy && isa<LLVM::LLVMPointerType>(srcTy)) {
1123 rewriter.replaceOp(op, adaptor.getInstance());
1126 return rewriter.notifyMatchFailure(
1127 op,
"Upcast applied to non-opaque pointers!");
1133 ClassNewOpConversion(TypeConverter &tc, MLIRContext *ctx,
1134 ClassTypeCache &cache, FunctionCache &funcCache)
1135 : OpConversionPattern<ClassNewOp>(tc, ctx), cache(cache),
1136 funcCache(funcCache) {}
1139 matchAndRewrite(ClassNewOp op, OpAdaptor adaptor,
1140 ConversionPatternRewriter &rewriter)
const override {
1141 Location loc = op.getLoc();
1142 MLIRContext *ctx = rewriter.getContext();
1144 auto handleTy = cast<ClassHandleType>(op.getResult().getType());
1145 auto sym = handleTy.getClassSym();
1147 ModuleOp mod = op->getParentOfType<ModuleOp>();
1149 if (failed(resolveClassStructBody(mod, sym, *typeConverter, cache)))
1150 return op.emitError() <<
"Could not resolve class struct for " << sym;
1152 auto structTy = cache.getStructInfo(sym)->classBody;
1153 auto typeInfo = cache.getStructInfo(sym)->typeInfo;
1158 for (
auto memberTy : structTy.getBody()) {
1159 if (!LLVM::isCompatibleType(memberTy) &&
1160 !memberTy.hasTrait<DataLayoutTypeInterface::Trait>()) {
1161 return op.emitError()
1162 <<
"class struct has member types with no data layout";
1168 uint64_t byteSize = dl.getTypeSize(structTy);
1169 auto i64Ty = IntegerType::get(ctx, 64);
1170 auto cSize = LLVM::ConstantOp::create(rewriter, loc, i64Ty,
1171 rewriter.getI64IntegerAttr(byteSize));
1174 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
1175 auto mallocFn = funcCache.getOrCreate(rewriter,
"malloc", {i64Ty}, {ptrTy});
1177 func::CallOp::create(rewriter, loc, mallocFn, ValueRange{cSize});
1180 LLVM::AddressOfOp::create(rewriter, loc, typeInfo.global);
1181 auto i32Ty = IntegerType::get(ctx, 32);
1182 auto headerIdx = LLVM::ConstantOp::create(
1183 rewriter, loc, i32Ty,
1184 rewriter.getI32IntegerAttr(cache.getStructInfo(sym)->headerFieldIndex));
1185 auto typeInfoIdx = LLVM::ConstantOp::create(
1186 rewriter, loc, i32Ty,
1187 rewriter.getI32IntegerAttr(
1188 cache.getStructInfo(sym)->typeInfoFieldIndex));
1190 LLVM::GEPOp::create(rewriter, loc, ptrTy, structTy, call.getResult(0),
1191 ValueRange{headerIdx, typeInfoIdx});
1192 LLVM::StoreOp::create(rewriter, loc, typeInfoAddr, headerPtr);
1196 rewriter.replaceOp(op, call.getResult(0));
1201 ClassTypeCache &cache;
1202 FunctionCache &funcCache;
1206 ClassDeclOpConversion(TypeConverter &tc, MLIRContext *ctx,
1207 ClassTypeCache &cache)
1208 : OpConversionPattern<ClassDeclOp>(tc, ctx), cache(cache) {}
1211 matchAndRewrite(ClassDeclOp op, OpAdaptor,
1212 ConversionPatternRewriter &rewriter)
const override {
1214 if (failed(resolveClassStructBody(op, *typeConverter, cache)))
1217 rewriter.eraseOp(op);
1222 ClassTypeCache &cache;
1226 using OpConversionPattern::OpConversionPattern;
1229 matchAndRewrite(VariableOp op, OpAdaptor adaptor,
1230 ConversionPatternRewriter &rewriter)
const override {
1231 auto loc = op.getLoc();
1232 auto resultType = typeConverter->convertType(op.getResult().getType());
1234 return rewriter.notifyMatchFailure(op.getLoc(),
"invalid variable type");
1236 auto refType = dyn_cast<llhd::RefType>(resultType);
1238 return rewriter.notifyMatchFailure(
1239 op.getLoc(),
"variable type did not convert to llhd::RefType");
1241 Value init = adaptor.getInitial();
1243 cast<moore::RefType>(op.getResult().getType()).getNestedType();
1247 if (!init && (sourceType.getDomain() == moore::Domain::TwoValued ||
1248 !sourceType.getBitSize())) {
1254 rewriter.replaceOpWithNewOp<llhd::SignalOp>(op, resultType,
1255 op.getNameAttr(), init);
1261 using OpConversionPattern::OpConversionPattern;
1264 matchAndRewrite(NetOp op, OpAdaptor adaptor,
1265 ConversionPatternRewriter &rewriter)
const override {
1266 auto loc = op.getLoc();
1268 auto resultType = typeConverter->convertType(op.getResult().getType());
1270 return rewriter.notifyMatchFailure(loc,
"invalid net type");
1272 auto elementType = cast<llhd::RefType>(resultType).getNestedType();
1278 createInitialValue(op.getKind(), rewriter, loc, width,
elementType);
1279 auto signal = rewriter.replaceOpWithNewOp<llhd::SignalOp>(
1280 op, resultType, op.getNameAttr(), init);
1282 if (
auto assignedValue = adaptor.getAssignment()) {
1283 llhd::AssignOp::create(rewriter, loc, signal, assignedValue, Value{});
1289 static mlir::Value createInitialValue(NetKind kind,
1290 ConversionPatternRewriter &rewriter,
1291 Location loc, int64_t width,
1302 if (kind == NetKind::Supply1 || kind == NetKind::Tri1)
1303 return APInt::getAllOnes(width);
1304 return APInt::getZero(width);
1307 return rewriter.createOrFold<hw::BitcastOp>(loc,
elementType, theConst);
1312static LogicalResult
convert(GlobalVariableOp op,
1313 GlobalVariableOp::Adaptor adaptor,
1314 ConversionPatternRewriter &rewriter,
1315 const TypeConverter &typeConverter) {
1316 auto type = typeConverter.convertType(op.getType());
1318 llhd::GlobalSignalOp::create(rewriter, op.getLoc(), op.getSymNameAttr(),
1320 sig.getInitRegion().takeBody(op.getInitRegion());
1321 rewriter.eraseOp(op);
1326static LogicalResult
convert(GetGlobalVariableOp op,
1327 GetGlobalVariableOp::Adaptor adaptor,
1328 ConversionPatternRewriter &rewriter,
1329 const TypeConverter &typeConverter) {
1330 auto type = typeConverter.convertType(op.getType());
1331 rewriter.replaceOpWithNewOp<llhd::GetGlobalSignalOp>(op, type,
1332 op.getGlobalNameAttr());
1341 using OpConversionPattern::OpConversionPattern;
1344 matchAndRewrite(ConstantOp op, OpAdaptor adaptor,
1345 ConversionPatternRewriter &rewriter)
const override {
1347 auto value = op.getValue().toAPInt(
false);
1348 auto type = rewriter.getIntegerType(value.getBitWidth());
1349 rewriter.replaceOpWithNewOp<hw::ConstantOp>(
1350 op, type, rewriter.getIntegerAttr(type, value));
1356 using OpConversionPattern::OpConversionPattern;
1359 matchAndRewrite(ConstantRealOp op, OpAdaptor adaptor,
1360 ConversionPatternRewriter &rewriter)
const override {
1361 rewriter.replaceOpWithNewOp<arith::ConstantOp>(op, op.getValueAttr());
1367 using OpConversionPattern::OpConversionPattern;
1370 matchAndRewrite(ConstantTimeOp op, OpAdaptor adaptor,
1371 ConversionPatternRewriter &rewriter)
const override {
1372 rewriter.replaceOpWithNewOp<llhd::ConstantTimeOp>(
1373 op, llhd::TimeAttr::get(op->getContext(), op.getValue(),
1374 StringRef(
"fs"), 0));
1380 using OpConversionPattern::OpConversionPattern;
1382 matchAndRewrite(moore::ConstantStringOp op, OpAdaptor adaptor,
1383 ConversionPatternRewriter &rewriter)
const override {
1384 const auto resultType =
1385 typeConverter->convertType(op.getResult().getType());
1386 const auto intType = mlir::cast<IntegerType>(resultType);
1388 const auto str = op.getValue();
1389 const unsigned byteWidth = intType.getWidth();
1390 APInt value(byteWidth, 0);
1393 const size_t maxChars =
1394 std::min(str.size(),
static_cast<size_t>(byteWidth / 8));
1395 for (
size_t i = 0; i < maxChars; i++) {
1396 const size_t pos = str.size() - 1 - i;
1397 const auto asciiChar =
static_cast<uint8_t
>(str[pos]);
1398 value |= APInt(byteWidth, asciiChar) << (8 * i);
1401 rewriter.replaceOpWithNewOp<hw::ConstantOp>(
1402 op, resultType, rewriter.getIntegerAttr(resultType, value));
1408 using OpConversionPattern::OpConversionPattern;
1410 matchAndRewrite(ConcatOp op, OpAdaptor adaptor,
1411 ConversionPatternRewriter &rewriter)
const override {
1412 rewriter.replaceOpWithNewOp<comb::ConcatOp>(op, adaptor.getValues());
1418 using OpConversionPattern::OpConversionPattern;
1420 matchAndRewrite(ReplicateOp op, OpAdaptor adaptor,
1421 ConversionPatternRewriter &rewriter)
const override {
1422 Type resultType = typeConverter->convertType(op.getResult().getType());
1424 rewriter.replaceOpWithNewOp<comb::ReplicateOp>(op, resultType,
1425 adaptor.getValue());
1431 using OpConversionPattern::OpConversionPattern;
1434 matchAndRewrite(ExtractOp op, OpAdaptor adaptor,
1435 ConversionPatternRewriter &rewriter)
const override {
1438 Type resultType = typeConverter->convertType(op.getResult().getType());
1439 Value input = adaptor.getInput();
1440 Type inputType = input.getType();
1441 int32_t low = adaptor.getLowBit();
1442 auto loc = op.getLoc();
1445 if (isa<IntegerType>(inputType)) {
1446 int32_t inputWidth = inputType.getIntOrFloatBitWidth();
1447 int32_t resultWidth = hw::getBitWidth(resultType);
1448 if (resultWidth < 0)
1451 int32_t high = low + resultWidth;
1452 int32_t lsbPad = std::clamp(-low, 0, resultWidth);
1453 int32_t msbPad = std::clamp(high - inputWidth, 0, resultWidth - lsbPad);
1454 int32_t extractWidth = resultWidth - lsbPad - msbPad;
1456 SmallVector<Value> sbv;
1460 if (extractWidth > 0)
1461 sbv.push_back(rewriter.createOrFold<comb::ExtractOp>(
1462 loc, rewriter.getIntegerType(extractWidth), input,
1468 Value res = rewriter.createOrFold<comb::ConcatOp>(loc, sbv);
1469 if (res.getType() != resultType)
1470 res = rewriter.createOrFold<hw::BitcastOp>(loc, resultType, res);
1472 rewriter.replaceOp(op, res);
1477 if (
auto arrTy = dyn_cast<hw::ArrayType>(inputType)) {
1479 int32_t idxWidth = llvm::Log2_64_Ceil(arrTy.getNumElements());
1480 int32_t inputWidth = arrTy.getNumElements();
1484 if (low < 0 || low >= inputWidth) {
1488 rewriter.replaceOp(op, zeros);
1490 rewriter.replaceOpWithNewOp<hw::ArrayGetOp>(
1493 rewriter.getIntegerType(idxWidth), low));
1499 if (
auto resArrTy = dyn_cast<hw::ArrayType>(resultType);
1500 resArrTy && resArrTy.getElementType() ==
elementType) {
1501 int32_t resultWidth = resArrTy.getNumElements();
1502 int32_t high = low + resultWidth;
1504 int32_t lsbPad = std::clamp(-low, 0, resultWidth);
1505 int32_t msbPad = std::clamp(high - inputWidth, 0, resultWidth - lsbPad);
1506 int32_t extractWidth = resultWidth - lsbPad - msbPad;
1508 SmallVector<Value> toConcat;
1514 toConcat.push_back(zeros);
1517 if (extractWidth > 0)
1518 toConcat.push_back(rewriter.createOrFold<hw::ArraySliceOp>(
1519 loc, hw::ArrayType::get(
elementType, extractWidth), input,
1521 rewriter.getIntegerType(idxWidth),
1522 std::max(low, 0))));
1529 toConcat.push_back(zeros);
1533 op, rewriter.createOrFold<hw::ArrayConcatOp>(loc, toConcat));
1543 using OpConversionPattern::OpConversionPattern;
1546 matchAndRewrite(ExtractRefOp op, OpAdaptor adaptor,
1547 ConversionPatternRewriter &rewriter)
const override {
1549 Type resultType = typeConverter->convertType(op.getResult().getType());
1550 auto inputRefType = dyn_cast<llhd::RefType>(adaptor.getInput().getType());
1552 return op.emitOpError(
1553 "extracts from a net which is not currently supported");
1554 auto inputType = inputRefType.getNestedType();
1556 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1557 int64_t width = hw::getBitWidth(inputType);
1562 rewriter, op.getLoc(),
1563 rewriter.getIntegerType(llvm::Log2_64_Ceil(width)),
1564 adaptor.getLowBit());
1565 rewriter.replaceOpWithNewOp<llhd::SigExtractOp>(
1566 op, resultType, adaptor.getInput(), lowBit);
1570 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1572 rewriter, op.getLoc(),
1573 rewriter.getIntegerType(llvm::Log2_64_Ceil(arrType.getNumElements())),
1574 adaptor.getLowBit());
1578 if (arrType.getElementType() !=
1579 cast<llhd::RefType>(resultType).getNestedType()) {
1580 rewriter.replaceOpWithNewOp<llhd::SigArraySliceOp>(
1581 op, resultType, adaptor.getInput(), lowBit);
1585 rewriter.replaceOpWithNewOp<llhd::SigArrayGetOp>(op, adaptor.getInput(),
1595 using OpConversionPattern::OpConversionPattern;
1598 matchAndRewrite(DynExtractOp op, OpAdaptor adaptor,
1599 ConversionPatternRewriter &rewriter)
const override {
1600 Type resultType = typeConverter->convertType(op.getResult().getType());
1601 Type inputType = adaptor.getInput().getType();
1603 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1604 Value amount = adjustIntegerWidth(rewriter, adaptor.getLowBit(),
1605 intType.getWidth(), op->getLoc());
1606 Value value = comb::ShrUOp::create(rewriter, op->getLoc(),
1607 adaptor.getInput(), amount);
1609 rewriter.replaceOpWithNewOp<comb::ExtractOp>(op, resultType, value, 0);
1613 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1614 unsigned idxWidth = llvm::Log2_64_Ceil(arrType.getNumElements());
1615 Value idx = adjustIntegerWidth(rewriter, adaptor.getLowBit(), idxWidth,
1618 bool isSingleElementExtract = arrType.getElementType() == resultType;
1620 if (isSingleElementExtract)
1621 rewriter.replaceOpWithNewOp<hw::ArrayGetOp>(op, adaptor.getInput(),
1624 rewriter.replaceOpWithNewOp<hw::ArraySliceOp>(op, resultType,
1625 adaptor.getInput(), idx);
1635 using OpConversionPattern::OpConversionPattern;
1638 matchAndRewrite(DynExtractRefOp op, OpAdaptor adaptor,
1639 ConversionPatternRewriter &rewriter)
const override {
1641 Type resultType = typeConverter->convertType(op.getResult().getType());
1642 auto inputRefType = dyn_cast<llhd::RefType>(adaptor.getInput().getType());
1644 return op.emitOpError(
1645 "extracts from a net which is not currently supported");
1646 auto inputType = inputRefType.getNestedType();
1648 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1649 int64_t width = hw::getBitWidth(inputType);
1654 adjustIntegerWidth(rewriter, adaptor.getLowBit(),
1655 llvm::Log2_64_Ceil(width), op->getLoc());
1656 rewriter.replaceOpWithNewOp<llhd::SigExtractOp>(
1657 op, resultType, adaptor.getInput(), amount);
1661 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1662 Value idx = adjustIntegerWidth(
1663 rewriter, adaptor.getLowBit(),
1664 llvm::Log2_64_Ceil(arrType.getNumElements()), op->getLoc());
1666 auto resultNestedType = cast<llhd::RefType>(resultType).getNestedType();
1667 bool isSingleElementExtract =
1668 arrType.getElementType() == resultNestedType;
1670 if (isSingleElementExtract)
1671 rewriter.replaceOpWithNewOp<llhd::SigArrayGetOp>(op, adaptor.getInput(),
1674 rewriter.replaceOpWithNewOp<llhd::SigArraySliceOp>(
1675 op, resultType, adaptor.getInput(), idx);
1685 using OpConversionPattern::OpConversionPattern;
1688 matchAndRewrite(ArrayCreateOp op, OpAdaptor adaptor,
1689 ConversionPatternRewriter &rewriter)
const override {
1690 Type resultType = typeConverter->convertType(op.getResult().getType());
1691 rewriter.replaceOpWithNewOp<hw::ArrayCreateOp>(op, resultType,
1692 adaptor.getElements());
1698 using OpConversionPattern::OpConversionPattern;
1701 matchAndRewrite(StructCreateOp op, OpAdaptor adaptor,
1702 ConversionPatternRewriter &rewriter)
const override {
1703 Type resultType = typeConverter->convertType(op.getResult().getType());
1704 rewriter.replaceOpWithNewOp<hw::StructCreateOp>(op, resultType,
1705 adaptor.getFields());
1711 using OpConversionPattern::OpConversionPattern;
1714 matchAndRewrite(StructExtractOp op, OpAdaptor adaptor,
1715 ConversionPatternRewriter &rewriter)
const override {
1716 rewriter.replaceOpWithNewOp<hw::StructExtractOp>(
1717 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1722struct StructExtractRefOpConversion
1724 using OpConversionPattern::OpConversionPattern;
1727 matchAndRewrite(StructExtractRefOp op, OpAdaptor adaptor,
1728 ConversionPatternRewriter &rewriter)
const override {
1729 rewriter.replaceOpWithNewOp<llhd::SigStructExtractOp>(
1730 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1736 using OpConversionPattern::OpConversionPattern;
1739 matchAndRewrite(UnionCreateOp op, OpAdaptor adaptor,
1740 ConversionPatternRewriter &rewriter)
const override {
1741 Type resultType = typeConverter->convertType(op.getResult().getType());
1742 rewriter.replaceOpWithNewOp<hw::UnionCreateOp>(
1743 op, resultType, adaptor.getFieldNameAttr(), adaptor.getInput());
1749 using OpConversionPattern::OpConversionPattern;
1752 matchAndRewrite(UnionExtractOp op, OpAdaptor adaptor,
1753 ConversionPatternRewriter &rewriter)
const override {
1754 rewriter.replaceOpWithNewOp<hw::UnionExtractOp>(op, adaptor.getInput(),
1755 adaptor.getFieldNameAttr());
1760struct UnionExtractRefOpConversion
1762 using OpConversionPattern::OpConversionPattern;
1765 matchAndRewrite(UnionExtractRefOp op, OpAdaptor adaptor,
1766 ConversionPatternRewriter &rewriter)
const override {
1767 rewriter.replaceOpWithNewOp<llhd::SigStructExtractOp>(
1768 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1774 using OpConversionPattern::OpConversionPattern;
1776 matchAndRewrite(ReduceAndOp op, OpAdaptor adaptor,
1777 ConversionPatternRewriter &rewriter)
const override {
1778 Type resultType = typeConverter->convertType(op.getInput().getType());
1781 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::eq,
1782 adaptor.getInput(), max);
1788 using OpConversionPattern::OpConversionPattern;
1790 matchAndRewrite(ReduceOrOp op, OpAdaptor adaptor,
1791 ConversionPatternRewriter &rewriter)
const override {
1792 Type resultType = typeConverter->convertType(op.getInput().getType());
1795 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1796 adaptor.getInput(), zero);
1802 using OpConversionPattern::OpConversionPattern;
1804 matchAndRewrite(ReduceXorOp op, OpAdaptor adaptor,
1805 ConversionPatternRewriter &rewriter)
const override {
1807 rewriter.replaceOpWithNewOp<comb::ParityOp>(op, adaptor.getInput());
1813 using OpConversionPattern::OpConversionPattern;
1815 matchAndRewrite(BoolCastOp op, OpAdaptor adaptor,
1816 ConversionPatternRewriter &rewriter)
const override {
1817 Type resultType = typeConverter->convertType(op.getInput().getType());
1818 if (isa_and_nonnull<IntegerType>(resultType)) {
1821 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1822 adaptor.getInput(), zero);
1825 if (isa_and_nonnull<FloatType>(resultType)) {
1826 Value zero = arith::ConstantOp::create(
1827 rewriter, op->getLoc(), rewriter.getFloatAttr(resultType, 0.0));
1828 rewriter.replaceOpWithNewOp<arith::CmpFOp>(op, arith::CmpFPredicate::ONE,
1829 adaptor.getInput(), zero);
1832 if (isa_and_nonnull<llhd::TimeType>(resultType)) {
1834 llhd::TimeToIntOp::create(rewriter, op->getLoc(), adaptor.getInput());
1836 rewriter.getI64Type(), 0);
1837 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1841 if (isa_and_nonnull<hw::StructType, hw::ArrayType, hw::UnionType>(
1843 int64_t width = hw::getBitWidth(resultType);
1846 auto intTy = rewriter.getIntegerType(width);
1847 Value input = rewriter.createOrFold<hw::BitcastOp>(op->getLoc(), intTy,
1848 adaptor.getInput());
1850 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1859 using OpConversionPattern::OpConversionPattern;
1861 matchAndRewrite(NotOp op, OpAdaptor adaptor,
1862 ConversionPatternRewriter &rewriter)
const override {
1864 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1867 rewriter.replaceOpWithNewOp<comb::XorOp>(op, adaptor.getInput(), max);
1873 using OpConversionPattern::OpConversionPattern;
1875 matchAndRewrite(NegOp op, OpAdaptor adaptor,
1876 ConversionPatternRewriter &rewriter)
const override {
1878 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1881 rewriter.replaceOpWithNewOp<comb::SubOp>(op, zero, adaptor.getInput());
1887 using OpConversionPattern::OpConversionPattern;
1889 matchAndRewrite(NegRealOp op, OpAdaptor adaptor,
1890 ConversionPatternRewriter &rewriter)
const override {
1891 rewriter.replaceOpWithNewOp<arith::NegFOp>(op, adaptor.getInput());
1896template <
typename SourceOp,
typename TargetOp>
1898 using OpConversionPattern<SourceOp>::OpConversionPattern;
1899 using OpAdaptor =
typename SourceOp::Adaptor;
1902 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1903 ConversionPatternRewriter &rewriter)
const override {
1904 rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(),
1905 adaptor.getRhs(),
false);
1910template <
typename SourceOp,
typename TargetOp>
1912 using OpConversionPattern<SourceOp>::OpConversionPattern;
1913 using OpAdaptor =
typename SourceOp::Adaptor;
1916 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1917 ConversionPatternRewriter &rewriter)
const override {
1918 rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(),
1925 using OpConversionPattern::OpConversionPattern;
1927 matchAndRewrite(HypotBIOp op, OpAdaptor adaptor,
1928 ConversionPatternRewriter &rewriter)
const override {
1929 Value lhs = adaptor.getLhs();
1930 Value rhs = adaptor.getRhs();
1931 ImplicitLocOpBuilder b(op->getLoc(), rewriter);
1932 auto left = arith::MulFOp::create(b, lhs, lhs);
1933 auto right = arith::MulFOp::create(b, rhs, rhs);
1934 auto sum = arith::AddFOp::create(b, left, right);
1935 auto out = math::SqrtOp::create(b, sum);
1936 rewriter.replaceOp(op, out);
1941template <
typename SourceOp,
typename TargetOp>
1943 using OpConversionPattern<SourceOp>::OpConversionPattern;
1944 using OpAdaptor =
typename SourceOp::Adaptor;
1947 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1948 ConversionPatternRewriter &rewriter)
const override {
1949 rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getValue());
1954template <
typename SourceOp, ICmpPredicate pred>
1956 using OpConversionPattern<SourceOp>::OpConversionPattern;
1957 using OpAdaptor =
typename SourceOp::Adaptor;
1960 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1961 ConversionPatternRewriter &rewriter)
const override {
1963 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1965 rewriter.replaceOpWithNewOp<comb::ICmpOp>(
1966 op, resultType, pred, adaptor.getLhs(), adaptor.getRhs());
1971template <
typename SourceOp>
1973 using OpConversionPattern<SourceOp>::OpConversionPattern;
1974 using OpConversionPattern<SourceOp>::getTypeConverter;
1975 using OpAdaptor =
typename SourceOp::Adaptor;
1978 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1979 ConversionPatternRewriter &rewriter)
const override {
1980 Type ptrTy = getTypeConverter()->convertType(op.getResult().getType());
1982 return rewriter.notifyMatchFailure(op,
"failed to convert null type");
1983 rewriter.replaceOpWithNewOp<LLVM::ZeroOp>(op, ptrTy);
1988template <
typename SourceOp, LLVM::ICmpPredicate pred>
1990 using OpConversionPattern<SourceOp>::OpConversionPattern;
1991 using OpAdaptor =
typename SourceOp::Adaptor;
1994 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1995 ConversionPatternRewriter &rewriter)
const override {
1996 rewriter.replaceOpWithNewOp<LLVM::ICmpOp>(op, pred, adaptor.getLhs(),
2002template <
typename SourceOp, arith::CmpFPredicate pred>
2004 using OpConversionPattern<SourceOp>::OpConversionPattern;
2005 using OpAdaptor =
typename SourceOp::Adaptor;
2008 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
2009 ConversionPatternRewriter &rewriter)
const override {
2011 ConversionPattern::typeConverter->convertType(op.getResult().getType());
2013 rewriter.replaceOpWithNewOp<arith::CmpFOp>(
2014 op, resultType, pred, adaptor.getLhs(), adaptor.getRhs());
2020static std::optional<FVInt> getFourValuedConstant(Value value) {
2021 if (
auto constOp = value.getDefiningOp<ConstantOp>())
2022 return constOp.getValue();
2023 return std::nullopt;
2036static Value lowerMaskedCaseCompare(ConversionPatternRewriter &rewriter,
2037 Location loc, Value lhsOrig, Value rhsOrig,
2038 Value lhs, Value rhs, APInt ignoredBits,
2039 ICmpPredicate pred,
bool negate) {
2040 auto lhsConst = getFourValuedConstant(lhsOrig);
2041 auto rhsConst = getFourValuedConstant(rhsOrig);
2042 auto constantResult = [&](
bool equal) -> Value {
2045 if (lhsConst && rhsConst) {
2047 APInt keep = ~ignoredBits;
2049 (lhsConst->getRawValue() & keep) == (rhsConst->getRawValue() & keep) &&
2050 (lhsConst->getRawUnknown() & keep) ==
2051 (rhsConst->getRawUnknown() & keep);
2052 return constantResult(equal);
2054 for (
auto &constant : {lhsConst, rhsConst})
2055 if (constant && !(constant->getUnknownBits() & ~ignoredBits).isZero())
2056 return constantResult(
false);
2057 if (!ignoredBits.isZero()) {
2059 lhs = rewriter.createOrFold<
comb::AndOp>(loc, lhs, maskOp);
2060 rhs = rewriter.createOrFold<
comb::AndOp>(loc, rhs, maskOp);
2062 return comb::ICmpOp::create(rewriter, loc, pred, lhs, rhs);
2066template <
typename SourceOp, ICmpPredicate pred,
bool negate>
2068 using OpConversionPattern<SourceOp>::OpConversionPattern;
2069 using OpAdaptor =
typename SourceOp::Adaptor;
2072 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
2073 ConversionPatternRewriter &rewriter)
const override {
2074 unsigned bitWidth = op.getLhs().getType().getWidth();
2075 rewriter.replaceOp(op, lowerMaskedCaseCompare(
2076 rewriter, op.getLoc(), op.getLhs(), op.getRhs(),
2077 adaptor.getLhs(), adaptor.getRhs(),
2078 APInt::getZero(bitWidth), pred, negate));
2087template <
typename SourceOp, ICmpPredicate pred,
bool negate>
2089 using OpConversionPattern<SourceOp>::OpConversionPattern;
2090 using OpAdaptor =
typename SourceOp::Adaptor;
2093 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
2094 ConversionPatternRewriter &rewriter)
const override {
2095 unsigned bitWidth = op.getLhs().getType().getWidth();
2096 auto lhsConst = getFourValuedConstant(op.getLhs());
2097 auto rhsConst = getFourValuedConstant(op.getRhs());
2098 Value lhs = adaptor.getLhs();
2099 Value rhs = adaptor.getRhs();
2100 if (lhsConst && lhsConst->hasUnknown()) {
2101 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, pred, lhs, rhs);
2105 rhsConst ? rhsConst->getUnknownBits() : APInt::getZero(bitWidth);
2106 rewriter.replaceOp(op, lowerMaskedCaseCompare(
2107 rewriter, op.getLoc(), op.getLhs(), op.getRhs(),
2108 lhs, rhs, ignoredBits, pred, negate));
2115template <
typename SourceOp,
bool withoutX>
2117 using OpConversionPattern<SourceOp>::OpConversionPattern;
2118 using OpAdaptor =
typename SourceOp::Adaptor;
2121 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
2122 ConversionPatternRewriter &rewriter)
const override {
2128 unsigned bitWidth = op.getLhs().getType().getWidth();
2129 auto ignoredBits = APInt::getZero(bitWidth);
2130 auto detectIgnoredBits = [&](Value value) {
2131 auto constValue = getFourValuedConstant(value);
2135 ignoredBits |= constValue->getZBits();
2137 ignoredBits |= constValue->getUnknownBits();
2139 detectIgnoredBits(op.getLhs());
2140 detectIgnoredBits(op.getRhs());
2142 rewriter.replaceOp(op, lowerMaskedCaseCompare(
2143 rewriter, op.getLoc(), op.getLhs(), op.getRhs(),
2144 adaptor.getLhs(), adaptor.getRhs(), ignoredBits,
2145 ICmpPredicate::ceq,
false));
2154template <
typename SourceOp>
2156 using OpConversionPattern<SourceOp>::OpConversionPattern;
2157 using OpAdaptor =
typename SourceOp::Adaptor;
2158 using ConversionPattern::typeConverter;
2161 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
2162 ConversionPatternRewriter &rewriter)
const override {
2163 auto type = typeConverter->convertType(op.getResult().getType());
2164 if (type == adaptor.getInput().getType())
2165 rewriter.replaceOp(op, adaptor.getInput());
2167 rewriter.replaceOpWithNewOp<hw::BitcastOp>(op, type, adaptor.getInput());
2173template <
typename SourceOp>
2175 using OpConversionPattern<SourceOp>::OpConversionPattern;
2176 using OpAdaptor =
typename SourceOp::Adaptor;
2177 using ConversionPattern::typeConverter;
2180 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
2181 ConversionPatternRewriter &rewriter)
const override {
2182 rewriter.replaceOp(op, adaptor.getInput());
2188 using OpConversionPattern::OpConversionPattern;
2191 matchAndRewrite(TruncOp op, OpAdaptor adaptor,
2192 ConversionPatternRewriter &rewriter)
const override {
2193 rewriter.replaceOpWithNewOp<comb::ExtractOp>(op, adaptor.getInput(), 0,
2194 op.getType().getWidth());
2200 using OpConversionPattern::OpConversionPattern;
2203 matchAndRewrite(ZExtOp op, OpAdaptor adaptor,
2204 ConversionPatternRewriter &rewriter)
const override {
2205 auto targetWidth = op.getType().getWidth();
2206 auto inputWidth = op.getInput().getType().getWidth();
2209 rewriter, op.getLoc(),
2210 rewriter.getIntegerType(targetWidth - inputWidth), 0);
2212 rewriter.replaceOpWithNewOp<comb::ConcatOp>(
2213 op, ValueRange{zeroExt, adaptor.getInput()});
2219 using OpConversionPattern::OpConversionPattern;
2222 matchAndRewrite(SExtOp op, OpAdaptor adaptor,
2223 ConversionPatternRewriter &rewriter)
const override {
2224 auto type = typeConverter->convertType(op.getType());
2226 comb::createOrFoldSExt(rewriter, op.getLoc(), adaptor.getInput(), type);
2227 rewriter.replaceOp(op, value);
2233 using OpConversionPattern::OpConversionPattern;
2236 matchAndRewrite(SIntToRealOp op, OpAdaptor adaptor,
2237 ConversionPatternRewriter &rewriter)
const override {
2238 rewriter.replaceOpWithNewOp<arith::SIToFPOp>(
2239 op, typeConverter->convertType(op.getType()), adaptor.getInput());
2245 using OpConversionPattern::OpConversionPattern;
2248 matchAndRewrite(UIntToRealOp op, OpAdaptor adaptor,
2249 ConversionPatternRewriter &rewriter)
const override {
2250 rewriter.replaceOpWithNewOp<arith::UIToFPOp>(
2251 op, typeConverter->convertType(op.getType()), adaptor.getInput());
2257 using OpConversionPattern::OpConversionPattern;
2260 matchAndRewrite(IntToStringOp op, OpAdaptor adaptor,
2261 ConversionPatternRewriter &rewriter)
const override {
2262 rewriter.replaceOpWithNewOp<sim::IntToStringOp>(op, adaptor.getInput());
2268 using OpConversionPattern::OpConversionPattern;
2271 matchAndRewrite(StringToIntOp op, OpAdaptor adaptor,
2272 ConversionPatternRewriter &rewriter)
const override {
2273 Type resultTy = typeConverter->convertType(op.getType());
2276 rewriter.replaceOpWithNewOp<sim::StringToIntOp>(op, resultTy,
2277 adaptor.getInput());
2282struct FormatStringToStringOpConversion
2284 using OpConversionPattern::OpConversionPattern;
2287 matchAndRewrite(FormatStringToStringOp op, OpAdaptor adaptor,
2288 ConversionPatternRewriter &rewriter)
const override {
2289 rewriter.replaceOpWithNewOp<sim::FormatToStringOp>(op,
2290 adaptor.getFmtstring());
2296 using OpConversionPattern::OpConversionPattern;
2299 matchAndRewrite(RealToIntOp op, OpAdaptor adaptor,
2300 ConversionPatternRewriter &rewriter)
const override {
2301 rewriter.replaceOpWithNewOp<arith::FPToSIOp>(
2302 op, typeConverter->convertType(op.getType()), adaptor.getInput());
2308 using OpConversionPattern::OpConversionPattern;
2311 matchAndRewrite(ConvertRealOp op, OpAdaptor adaptor,
2312 ConversionPatternRewriter &rewriter)
const override {
2313 auto resultType = typeConverter->convertType(op.getType());
2314 if (op.getInput().getType().getWidth() <
2315 op.getResult().getType().getWidth()) {
2316 arith::ExtFOp::Properties properties{};
2317 arith::ExtFOp::populateDefaultProperties(
2318 OperationName(arith::ExtFOp::getOperationName(),
2319 rewriter.getContext()),
2321 rewriter.replaceOpWithNewOp<arith::ExtFOp>(op, TypeRange{resultType},
2322 ValueRange{adaptor.getInput()},
2325 arith::TruncFOp::Properties properties{};
2326 arith::TruncFOp::populateDefaultProperties(
2327 OperationName(arith::TruncFOp::getOperationName(),
2328 rewriter.getContext()),
2330 rewriter.replaceOpWithNewOp<arith::TruncFOp>(
2331 op, TypeRange{resultType}, ValueRange{adaptor.getInput()},
2338template <
typename SourceOp>
2340 using OpConversionPattern<SourceOp>::OpConversionPattern;
2341 using OpAdaptor =
typename SourceOp::Adaptor;
2344 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
2345 ConversionPatternRewriter &rewriter)
const override {
2347 ConversionPattern::typeConverter->convertType(op.getResult().getType());
2348 rewriter.replaceOpWithNewOp<arith::BitcastOp>(op, resultTy,
2349 adaptor.getValue());
2359 using OpConversionPattern::OpConversionPattern;
2362 matchAndRewrite(hw::InstanceOp op, OpAdaptor adaptor,
2363 ConversionPatternRewriter &rewriter)
const override {
2364 SmallVector<Type> convResTypes;
2365 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
2368 rewriter.replaceOpWithNewOp<hw::InstanceOp>(
2369 op, convResTypes, op.getInstanceName(), op.getModuleName(),
2370 adaptor.getOperands(), op.getArgNames(),
2371 op.getResultNames(),
2372 rewriter.getArrayAttr({}),
nullptr);
2379 using OpConversionPattern::OpConversionPattern;
2382 matchAndRewrite(func::ReturnOp op, OpAdaptor adaptor,
2383 ConversionPatternRewriter &rewriter)
const override {
2384 rewriter.replaceOpWithNewOp<func::ReturnOp>(op, adaptor.getOperands());
2390 using OpConversionPattern::OpConversionPattern;
2393 matchAndRewrite(func::CallOp op, OpAdaptor adaptor,
2394 ConversionPatternRewriter &rewriter)
const override {
2395 SmallVector<Type> convResTypes;
2396 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
2398 rewriter.replaceOpWithNewOp<func::CallOp>(
2399 op, adaptor.getCallee(), convResTypes, adaptor.getOperands());
2404struct FuncDPICallOpConversion
2406 using OpConversionPattern::OpConversionPattern;
2409 matchAndRewrite(moore::FuncDPICallOp op, OpAdaptor adaptor,
2410 ConversionPatternRewriter &rewriter)
const override {
2411 SmallVector<Type> convResTypes;
2412 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
2414 rewriter.replaceOpWithNewOp<sim::DPICallOp>(
2415 op, convResTypes, op.getCalleeAttr(), Value(),
2416 Value(), adaptor.getInputs());
2422 using OpConversionPattern::OpConversionPattern;
2425 matchAndRewrite(moore::DPIFuncOp op, OpAdaptor adaptor,
2426 ConversionPatternRewriter &rewriter)
const override {
2428 auto toDPIDir = [](moore::DPIArgDirection dir) -> sim::DPIDirection {
2430 case moore::DPIArgDirection::In:
2431 return sim::DPIDirection::Input;
2432 case moore::DPIArgDirection::Out:
2433 return sim::DPIDirection::Output;
2434 case moore::DPIArgDirection::InOut:
2435 return sim::DPIDirection::InOut;
2436 case moore::DPIArgDirection::Return:
2437 return sim::DPIDirection::Return;
2439 llvm_unreachable(
"unknown DPIArgDirection");
2443 auto dirs = op.getDpiArgDirs();
2444 auto names = op.getDpiArgNames();
2445 SmallVector<Type> argTypes;
2446 op.getDPIArgTypes(argTypes);
2448 SmallVector<sim::DPIArgument> dpiArguments;
2449 for (
auto [dirAttr, nameAttr, mooreType] :
2450 llvm::zip(dirs, names, argTypes)) {
2451 auto dir = toDPIDir(cast<moore::DPIArgDirectionAttr>(dirAttr).getValue());
2452 auto name = cast<StringAttr>(nameAttr);
2453 Type coreType = typeConverter->convertType(mooreType);
2455 return op.emitOpError(
"argument '")
2456 << name <<
"' has unsupported type " << mooreType;
2457 dpiArguments.push_back({name, coreType, dir});
2460 auto coreDPIFuncType =
2461 sim::DPIFunctionType::get(rewriter.getContext(), dpiArguments);
2462 auto simFunc = sim::DPIFuncOp::create(
2463 rewriter, op.getLoc(), op.getSymNameAttr(), coreDPIFuncType,
2464 op.getArgumentLocsAttr(), op.getVerilogNameAttr());
2465 SymbolTable::setSymbolVisibility(simFunc,
2466 SymbolTable::getSymbolVisibility(op));
2467 rewriter.eraseOp(op);
2472struct UnrealizedConversionCastConversion
2474 using OpConversionPattern::OpConversionPattern;
2477 matchAndRewrite(UnrealizedConversionCastOp op, OpAdaptor adaptor,
2478 ConversionPatternRewriter &rewriter)
const override {
2479 SmallVector<Type> convResTypes;
2480 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
2485 if (convResTypes == adaptor.getOperands().getTypes()) {
2486 rewriter.replaceOp(op, adaptor.getOperands());
2490 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
2491 op, convResTypes, adaptor.getOperands());
2497 using OpConversionPattern::OpConversionPattern;
2500 matchAndRewrite(ShlOp op, OpAdaptor adaptor,
2501 ConversionPatternRewriter &rewriter)
const override {
2502 Type resultType = typeConverter->convertType(op.getResult().getType());
2506 adjustIntegerWidth(rewriter, adaptor.getAmount(),
2507 resultType.getIntOrFloatBitWidth(), op->getLoc());
2508 rewriter.replaceOpWithNewOp<comb::ShlOp>(op, resultType, adaptor.getValue(),
2515 using OpConversionPattern::OpConversionPattern;
2518 matchAndRewrite(ShrOp op, OpAdaptor adaptor,
2519 ConversionPatternRewriter &rewriter)
const override {
2520 Type resultType = typeConverter->convertType(op.getResult().getType());
2524 adjustIntegerWidth(rewriter, adaptor.getAmount(),
2525 resultType.getIntOrFloatBitWidth(), op->getLoc());
2526 rewriter.replaceOpWithNewOp<comb::ShrUOp>(
2527 op, resultType, adaptor.getValue(), amount,
false);
2533 using OpConversionPattern::OpConversionPattern;
2536 matchAndRewrite(PowUOp op, OpAdaptor adaptor,
2537 ConversionPatternRewriter &rewriter)
const override {
2538 Type resultType = typeConverter->convertType(op.getResult().getType());
2540 Location loc = op->getLoc();
2545 auto lhs = comb::ConcatOp::create(rewriter, loc, zeroVal, adaptor.getLhs());
2546 auto rhs = comb::ConcatOp::create(rewriter, loc, zeroVal, adaptor.getRhs());
2549 auto pow = mlir::math::IPowIOp::create(rewriter, loc, lhs, rhs);
2551 rewriter.replaceOpWithNewOp<comb::ExtractOp>(op, resultType, pow, 0);
2557 using OpConversionPattern::OpConversionPattern;
2560 matchAndRewrite(PowSOp op, OpAdaptor adaptor,
2561 ConversionPatternRewriter &rewriter)
const override {
2562 Type resultType = typeConverter->convertType(op.getResult().getType());
2566 rewriter.replaceOpWithNewOp<mlir::math::IPowIOp>(
2567 op, resultType, adaptor.getLhs(), adaptor.getRhs());
2573 using OpConversionPattern::OpConversionPattern;
2576 matchAndRewrite(Clog2BIOp op, OpAdaptor adaptor,
2577 ConversionPatternRewriter &rewriter)
const override {
2578 Type resultType = typeConverter->convertType(op.getResult().getType());
2579 Location loc = op.getLoc();
2580 unsigned width = resultType.getIntOrFloatBitWidth();
2581 Value value = adaptor.getValue();
2590 Value valueMinusOne = comb::SubOp::create(rewriter, loc, value, one,
false);
2592 mlir::math::CountLeadingZerosOp::create(rewriter, loc, valueMinusOne);
2593 Value bitLength = comb::SubOp::create(rewriter, loc, bitWidth, clz,
false);
2595 Value isZero = comb::ICmpOp::create(rewriter, loc, comb::ICmpPredicate::eq,
2596 value, zero,
false);
2597 rewriter.replaceOpWithNewOp<comb::MuxOp>(op, isZero, zero, bitLength,
2604 using OpConversionPattern::OpConversionPattern;
2607 matchAndRewrite(AShrOp op, OpAdaptor adaptor,
2608 ConversionPatternRewriter &rewriter)
const override {
2609 Type resultType = typeConverter->convertType(op.getResult().getType());
2613 adjustIntegerWidth(rewriter, adaptor.getAmount(),
2614 resultType.getIntOrFloatBitWidth(), op->getLoc());
2615 rewriter.replaceOpWithNewOp<comb::ShrSOp>(
2616 op, resultType, adaptor.getValue(), amount,
false);
2622 using OpConversionPattern::OpConversionPattern;
2625 matchAndRewrite(ReadOp op, OpAdaptor adaptor,
2626 ConversionPatternRewriter &rewriter)
const override {
2627 if (isa<llhd::NetType>(adaptor.getInput().getType()))
2628 rewriter.replaceOpWithNewOp<llhd::ProbeNetOp>(op, adaptor.getInput());
2630 rewriter.replaceOpWithNewOp<llhd::ProbeOp>(op, adaptor.getInput());
2635struct AssignedVariableOpConversion
2637 using OpConversionPattern::OpConversionPattern;
2640 matchAndRewrite(AssignedVariableOp op, OpAdaptor adaptor,
2641 ConversionPatternRewriter &rewriter)
const override {
2642 rewriter.replaceOpWithNewOp<hw::WireOp>(op, adaptor.getInput(),
2643 adaptor.getNameAttr());
2648template <
typename OpTy>
2650 using OpConversionPattern<OpTy>::OpConversionPattern;
2651 using OpAdaptor =
typename OpTy::Adaptor;
2654 matchAndRewrite(OpTy op, OpAdaptor adaptor,
2655 ConversionPatternRewriter &rewriter)
const override {
2657 if constexpr (std::is_same_v<OpTy, ContinuousAssignOp> ||
2658 std::is_same_v<OpTy, BlockingAssignOp>) {
2659 if (isa<llhd::NetType>(adaptor.getDst().getType()))
2660 rewriter.replaceOpWithNewOp<llhd::AssignNetOp>(
2661 op, adaptor.getDst(), adaptor.getSrc(), Value{});
2663 rewriter.replaceOpWithNewOp<llhd::AssignOp>(op, adaptor.getDst(),
2664 adaptor.getSrc(), Value{});
2668 if constexpr (std::is_same_v<OpTy, NonBlockingAssignOp>) {
2670 delay = llhd::ConstantTimeOp::create(
2671 rewriter, op->getLoc(),
2672 llhd::TimeAttr::get(op->getContext(), 0U,
"ns", 1));
2675 delay = adaptor.getDelay();
2678 rewriter.replaceOpWithNewOp<llhd::DriveOp>(
2679 op, adaptor.getDst(), adaptor.getSrc(), delay, Value{});
2686 using OpConversionPattern::OpConversionPattern;
2689 matchAndRewrite(ConditionalOp op, OpAdaptor adaptor,
2690 ConversionPatternRewriter &rewriter)
const override {
2695 auto type = typeConverter->convertType(op.getType());
2697 auto hasNoWriteEffect = [](Region ®ion) {
2698 auto result = region.walk([](Operation *operation) {
2699 if (
auto memOp = dyn_cast<MemoryEffectOpInterface>(operation))
2700 if (!memOp.hasEffect<MemoryEffects::Write>() &&
2701 !memOp.hasEffect<MemoryEffects::Free>())
2702 return WalkResult::advance();
2704 if (operation->hasTrait<OpTrait::HasRecursiveMemoryEffects>())
2705 return WalkResult::advance();
2707 return WalkResult::interrupt();
2709 return !result.wasInterrupted();
2712 if (hasNoWriteEffect(op.getTrueRegion()) &&
2713 hasNoWriteEffect(op.getFalseRegion())) {
2714 Operation *trueTerm = op.getTrueRegion().front().getTerminator();
2715 Operation *falseTerm = op.getFalseRegion().front().getTerminator();
2717 rewriter.inlineBlockBefore(&op.getTrueRegion().front(), op);
2718 rewriter.inlineBlockBefore(&op.getFalseRegion().front(), op);
2720 Value convTrueVal = typeConverter->materializeTargetConversion(
2721 rewriter, op.getLoc(), type, trueTerm->getOperand(0));
2722 Value convFalseVal = typeConverter->materializeTargetConversion(
2723 rewriter, op.getLoc(), type, falseTerm->getOperand(0));
2725 rewriter.eraseOp(trueTerm);
2726 rewriter.eraseOp(falseTerm);
2728 rewriter.replaceOpWithNewOp<comb::MuxOp>(op, adaptor.getCondition(),
2729 convTrueVal, convFalseVal);
2734 scf::IfOp::create(rewriter, op.getLoc(), type, adaptor.getCondition());
2735 rewriter.inlineRegionBefore(op.getTrueRegion(), ifOp.getThenRegion(),
2736 ifOp.getThenRegion().end());
2737 rewriter.inlineRegionBefore(op.getFalseRegion(), ifOp.getElseRegion(),
2738 ifOp.getElseRegion().end());
2739 rewriter.replaceOp(op, ifOp);
2745 using OpConversionPattern::OpConversionPattern;
2748 matchAndRewrite(YieldOp op, OpAdaptor adaptor,
2749 ConversionPatternRewriter &rewriter)
const override {
2750 Operation *parent = op->getParentOp();
2751 if (isa<llhd::GlobalSignalOp>(parent))
2752 rewriter.replaceOpWithNewOp<llhd::YieldOp>(op, adaptor.getResult());
2753 else if (isa<scf::ExecuteRegionOp, scf::ForOp, scf::IfOp,
2754 scf::IndexSwitchOp, scf::WhileOp>(parent))
2755 rewriter.replaceOpWithNewOp<scf::YieldOp>(op, adaptor.getResult());
2757 return rewriter.notifyMatchFailure(
2758 op,
"yield parent has not been converted to a legal region op yet");
2763template <
typename SourceOp>
2765 using OpConversionPattern<SourceOp>::OpConversionPattern;
2766 using OpAdaptor =
typename SourceOp::Adaptor;
2769 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
2770 ConversionPatternRewriter &rewriter)
const override {
2771 rewriter.modifyOpInPlace(op,
2772 [&]() { op->setOperands(adaptor.getOperands()); });
2777template <
typename MooreOpTy,
typename VerifOpTy>
2779 using OpConversionPattern<MooreOpTy>::OpConversionPattern;
2780 using OpAdaptor =
typename MooreOpTy::Adaptor;
2783 matchAndRewrite(MooreOpTy op, OpAdaptor adaptor,
2784 ConversionPatternRewriter &rewriter)
const override {
2786 op.getLabel().has_value()
2787 ? StringAttr::get(op->getContext(), op.getLabel().value())
2788 : StringAttr::
get(op->getContext());
2789 rewriter.replaceOpWithNewOp<VerifOpTy>(op, adaptor.getCond(), mlir::Value(),
2800 using OpConversionPattern::OpConversionPattern;
2803 matchAndRewrite(FormatLiteralOp op, OpAdaptor adaptor,
2804 ConversionPatternRewriter &rewriter)
const override {
2805 rewriter.replaceOpWithNewOp<sim::FormatLiteralOp>(op, adaptor.getLiteral());
2811 using OpConversionPattern::OpConversionPattern;
2814 matchAndRewrite(FormatStringOp op, OpAdaptor adaptor,
2815 ConversionPatternRewriter &rewriter)
const override {
2817 op.getPadding().value_or(IntPadding::Space) == IntPadding::Space ? 32
2819 IntegerAttr padCharAttr = rewriter.getI8IntegerAttr(padChar);
2820 auto widthAttr = adaptor.getWidthAttr();
2822 bool isLeftAligned =
2823 op.getAlignment().value_or(IntAlign::Right) == IntAlign::Left;
2824 BoolAttr isLeftAlignedAttr = rewriter.getBoolAttr(isLeftAligned);
2826 rewriter.replaceOpWithNewOp<sim::FormatStringOp>(
2827 op, adaptor.getString(), isLeftAlignedAttr, padCharAttr, widthAttr);
2833 using OpConversionPattern::OpConversionPattern;
2836 matchAndRewrite(FormatConcatOp op, OpAdaptor adaptor,
2837 ConversionPatternRewriter &rewriter)
const override {
2838 rewriter.replaceOpWithNewOp<sim::FormatStringConcatOp>(op,
2839 adaptor.getInputs());
2844struct FormatHierPathOpConversion
2846 using OpConversionPattern::OpConversionPattern;
2849 matchAndRewrite(FormatHierPathOp op, OpAdaptor adaptor,
2850 ConversionPatternRewriter &rewriter)
const override {
2851 rewriter.replaceOpWithNewOp<sim::FormatHierPathOp>(op,
2852 adaptor.getUseEscapes());
2858 using OpConversionPattern::OpConversionPattern;
2861 matchAndRewrite(FormatIntOp op, OpAdaptor adaptor,
2862 ConversionPatternRewriter &rewriter)
const override {
2864 char padChar = adaptor.getPadding() == IntPadding::Space ? 32 : 48;
2865 IntegerAttr padCharAttr = rewriter.getI8IntegerAttr(padChar);
2866 auto widthAttr = adaptor.getSpecifierWidthAttr();
2868 bool isLeftAligned = adaptor.getAlignment() == IntAlign::Left;
2869 BoolAttr isLeftAlignedAttr = rewriter.getBoolAttr(isLeftAligned);
2871 switch (op.getFormat()) {
2872 case IntFormat::Decimal:
2873 rewriter.replaceOpWithNewOp<sim::FormatDecOp>(
2874 op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr,
2875 adaptor.getIsSignedAttr());
2877 case IntFormat::Binary:
2878 rewriter.replaceOpWithNewOp<sim::FormatBinOp>(
2879 op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr);
2881 case IntFormat::Octal:
2882 rewriter.replaceOpWithNewOp<sim::FormatOctOp>(
2883 op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr);
2885 case IntFormat::HexLower:
2886 rewriter.replaceOpWithNewOp<sim::FormatHexOp>(
2887 op, adaptor.getValue(), rewriter.getBoolAttr(
false),
2888 isLeftAlignedAttr, padCharAttr, widthAttr);
2890 case IntFormat::HexUpper:
2891 rewriter.replaceOpWithNewOp<sim::FormatHexOp>(
2892 op, adaptor.getValue(), rewriter.getBoolAttr(
true), isLeftAlignedAttr,
2893 padCharAttr, widthAttr);
2896 return rewriter.notifyMatchFailure(op,
"unsupported int format");
2901 using OpConversionPattern::OpConversionPattern;
2904 matchAndRewrite(FormatRealOp op, OpAdaptor adaptor,
2905 ConversionPatternRewriter &rewriter)
const override {
2906 auto fracDigitsAttr = adaptor.getFracDigitsAttr();
2908 auto fieldWidthAttr = adaptor.getFieldWidthAttr();
2909 bool isLeftAligned = adaptor.getAlignment() == IntAlign::Left;
2910 mlir::BoolAttr isLeftAlignedAttr = rewriter.getBoolAttr(isLeftAligned);
2912 switch (op.getFormat()) {
2913 case RealFormat::General:
2914 rewriter.replaceOpWithNewOp<sim::FormatGeneralOp>(
2915 op, adaptor.getValue(), isLeftAlignedAttr, fieldWidthAttr,
2918 case RealFormat::Float:
2919 rewriter.replaceOpWithNewOp<sim::FormatFloatOp>(
2920 op, adaptor.getValue(), isLeftAlignedAttr, fieldWidthAttr,
2923 case RealFormat::Exponential:
2924 rewriter.replaceOpWithNewOp<sim::FormatScientificOp>(
2925 op, adaptor.getValue(), isLeftAlignedAttr, fieldWidthAttr,
2932struct FormatCharOpConversion
2934 using OpConversionPattern::OpConversionPattern;
2936 matchAndRewrite(moore::FormatCharOp op, OpAdaptor adaptor,
2937 ConversionPatternRewriter &rewriter)
const override {
2938 rewriter.replaceOpWithNewOp<sim::FormatCharOp>(op, adaptor.getValue());
2944 using OpConversionPattern::OpConversionPattern;
2947 matchAndRewrite(StringLenOp op, OpAdaptor adaptor,
2948 ConversionPatternRewriter &rewriter)
const override {
2949 rewriter.replaceOpWithNewOp<sim::StringLengthOp>(op, adaptor.getStr());
2955 using OpConversionPattern::OpConversionPattern;
2958 matchAndRewrite(StringConcatOp op, OpAdaptor adaptor,
2959 ConversionPatternRewriter &rewriter)
const override {
2960 rewriter.replaceOpWithNewOp<sim::StringConcatOp>(op, adaptor.getInputs());
2966 using OpConversionPattern::OpConversionPattern;
2969 matchAndRewrite(StringGetOp op, OpAdaptor adaptor,
2970 ConversionPatternRewriter &rewriter)
const override {
2971 rewriter.replaceOpWithNewOp<sim::StringGetOp>(op, adaptor.getStr(),
2972 adaptor.getIndex());
2978 using OpConversionPattern::OpConversionPattern;
2981 matchAndRewrite(QueueSizeBIOp op, OpAdaptor adaptor,
2982 ConversionPatternRewriter &rewriter)
const override {
2983 rewriter.replaceOpWithNewOp<sim::QueueSizeOp>(op, adaptor.getQueue());
2988struct DynQueueExtractOpConversion
2990 using OpConversionPattern::OpConversionPattern;
2993 matchAndRewrite(DynQueueExtractOp op, OpAdaptor adaptor,
2994 ConversionPatternRewriter &rewriter)
const override {
2995 bool isSingleElementExtract =
2996 op.getInput().getType().getElementType() == op.getResult().getType();
2998 if (isSingleElementExtract) {
2999 rewriter.replaceOpWithNewOp<sim::QueueGetOp>(op, adaptor.getInput(),
3000 adaptor.getLowerIdx());
3002 rewriter.replaceOpWithNewOp<sim::QueueSliceOp>(
3003 op, adaptor.getInput(), adaptor.getLowerIdx(), adaptor.getUpperIdx());
3018static void probeRefAndAssignResult(OpBuilder &builder, Location loc, Value ref,
3019 const std::function<Value(Value)> &
func) {
3021 Value v = llhd::ProbeOp::create(builder, loc, ref);
3023 llhd::AssignOp::create(builder, loc, ref,
func(v), Value{});
3027 using OpConversionPattern::OpConversionPattern;
3030 matchAndRewrite(QueuePushBackOp op, OpAdaptor adaptor,
3031 ConversionPatternRewriter &rewriter)
const override {
3032 probeRefAndAssignResult(
3033 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
3034 return sim::QueuePushBackOp::create(rewriter, op->getLoc(), queue,
3035 adaptor.getElement());
3038 rewriter.eraseOp(op);
3043struct QueuePushFrontOpConversion
3045 using OpConversionPattern::OpConversionPattern;
3048 matchAndRewrite(QueuePushFrontOp op, OpAdaptor adaptor,
3049 ConversionPatternRewriter &rewriter)
const override {
3051 probeRefAndAssignResult(
3052 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
3053 return sim::QueuePushFrontOp::create(rewriter, op->getLoc(), queue,
3054 adaptor.getElement());
3057 rewriter.eraseOp(op);
3063 using OpConversionPattern::OpConversionPattern;
3066 matchAndRewrite(QueuePopBackOp op, OpAdaptor adaptor,
3067 ConversionPatternRewriter &rewriter)
const override {
3069 probeRefAndAssignResult(
3070 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
3072 sim::QueuePopBackOp::create(rewriter, op->getLoc(), queue);
3073 popped = popBack.getPopped();
3074 return popBack.getOutQueue();
3076 rewriter.replaceOp(op, popped);
3083 using OpConversionPattern::OpConversionPattern;
3086 matchAndRewrite(QueuePopFrontOp op, OpAdaptor adaptor,
3087 ConversionPatternRewriter &rewriter)
const override {
3089 probeRefAndAssignResult(
3090 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
3092 sim::QueuePopFrontOp::create(rewriter, op->getLoc(), queue);
3093 popped = popFront.getPopped();
3094 return popFront.getOutQueue();
3096 rewriter.replaceOp(op, popped);
3103 using OpConversionPattern::OpConversionPattern;
3106 matchAndRewrite(QueueClearOp op, OpAdaptor adaptor,
3107 ConversionPatternRewriter &rewriter)
const override {
3108 auto refType = cast<llhd::RefType>(adaptor.getQueue().getType());
3109 auto queueType = refType.getNestedType();
3111 sim::QueueEmptyOp::create(rewriter, op->getLoc(), queueType);
3114 llhd::AssignOp::create(rewriter, op.getLoc(), adaptor.getQueue(),
3115 emptyQueue, Value{});
3117 rewriter.eraseOp(op);
3123 using OpConversionPattern::OpConversionPattern;
3126 matchAndRewrite(QueueInsertOp op, OpAdaptor adaptor,
3127 ConversionPatternRewriter &rewriter)
const override {
3128 probeRefAndAssignResult(
3129 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
3131 sim::QueueInsertOp::create(rewriter, op->getLoc(), queue,
3132 adaptor.getIndex(), adaptor.getItem());
3134 return insert.getOutQueue();
3136 rewriter.eraseOp(op);
3143 using OpConversionPattern::OpConversionPattern;
3146 matchAndRewrite(QueueDeleteOp op, OpAdaptor adaptor,
3147 ConversionPatternRewriter &rewriter)
const override {
3148 probeRefAndAssignResult(
3149 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
3150 auto delOp = sim::QueueDeleteOp::create(rewriter, op->getLoc(), queue,
3151 adaptor.getIndex());
3153 return delOp.getOutQueue();
3155 rewriter.eraseOp(op);
3162 using OpConversionPattern::OpConversionPattern;
3165 matchAndRewrite(QueueResizeOp op, OpAdaptor adaptor,
3166 ConversionPatternRewriter &rewriter)
const override {
3168 rewriter.replaceOpWithNewOp<sim::QueueResizeOp>(
3169 op, getTypeConverter()->convertType(op.getResult().getType()),
3170 adaptor.getInput());
3176 using OpConversionPattern::OpConversionPattern;
3178 matchAndRewrite(QueueSetOp op, OpAdaptor adaptor,
3179 ConversionPatternRewriter &rewriter)
const override {
3180 probeRefAndAssignResult(
3181 rewriter, op->getLoc(), adaptor.getQueue(), [&](Value queue) {
3183 sim::QueueSetOp::create(rewriter, op.getLoc(), queue,
3184 adaptor.getIndex(), adaptor.getItem());
3185 return setOp.getOutQueue();
3187 rewriter.eraseOp(op);
3196static Value buildUArrayElementEq(ConversionPatternRewriter &rewriter,
3197 Location loc, Value lhs, Value rhs, Type type,
3198 UArrayCmpPredicate pred) {
3199 bool isEq = pred == UArrayCmpPredicate::eq;
3201 if (isa<mlir::FloatType>(type))
3202 return arith::CmpFOp::create(
3204 isEq ? arith::CmpFPredicate::OEQ : arith::CmpFPredicate::UNE, lhs, rhs);
3207 auto intTy = rewriter.getIntegerType(width);
3210 return comb::ICmpOp::create(rewriter, loc,
3211 isEq ? ICmpPredicate::eq : ICmpPredicate::ne,
3215 if (isa<sim::DynamicStringType>(type))
3216 return sim::StringCmpOp::create(rewriter, loc,
3217 isEq ? sim::StringCmpPredicate::eq
3218 : sim::StringCmpPredicate::ne,
3221 if (isa<sim::QueueType>(type)) {
3222 auto pred = sim::UArrayCmpPredicateAttr::get(
3223 rewriter.getContext(),
3224 isEq ? sim::UArrayCmpPredicate::eq : sim::UArrayCmpPredicate::ne);
3225 return sim::QueueCmpOp::create(rewriter, loc, pred, lhs, rhs);
3228 if (isa<sim::AssocArrayType>(type)) {
3229 auto pred = sim::UArrayCmpPredicateAttr::get(
3230 rewriter.getContext(),
3231 isEq ? sim::UArrayCmpPredicate::eq : sim::UArrayCmpPredicate::ne);
3232 return sim::AssocArrayCmpOp::create(rewriter, loc, pred, lhs, rhs);
3235 auto arrayTy = dyn_cast<hw::ArrayType>(type);
3239 unsigned size = arrayTy.getNumElements();
3243 unsigned idxWidth = size == 1 ? 1 : llvm::Log2_64_Ceil(size);
3244 auto idxTy = rewriter.getIntegerType(idxWidth);
3246 SmallVector<Value> elemEqs;
3247 elemEqs.reserve(size);
3248 for (
unsigned i = 0; i < size; ++i) {
3252 Value elemEq = buildUArrayElementEq(rewriter, loc, lhsElem, rhsElem,
3253 arrayTy.getElementType(), pred);
3256 elemEqs.push_back(elemEq);
3259 return (isEq ? comb::AndOp::create(rewriter, loc, elemEqs,
true)
3261 : comb::OrOp::create(rewriter, loc, elemEqs,
true)
3266 using OpConversionPattern::OpConversionPattern;
3269 matchAndRewrite(QueueCmpOp op, OpAdaptor adaptor,
3270 ConversionPatternRewriter &rewriter)
const override {
3275 Value lhs = adaptor.getLhs();
3277 buildUArrayElementEq(rewriter, op.getLoc(), lhs, adaptor.getRhs(),
3278 lhs.getType(), op.getPredicate());
3279 rewriter.replaceOp(op, result);
3284struct QueueFromUnpackedArrayOpConversion
3286 using OpConversionPattern::OpConversionPattern;
3289 matchAndRewrite(QueueFromUnpackedArrayOp op, OpAdaptor adaptor,
3290 ConversionPatternRewriter &rewriter)
const override {
3291 rewriter.replaceOpWithNewOp<sim::QueueFromArrayOp>(
3292 op, getTypeConverter()->convertType(op.getResult().getType()),
3293 adaptor.getInput());
3299 using OpConversionPattern::OpConversionPattern;
3302 matchAndRewrite(QueueConcatOp op, OpAdaptor adaptor,
3303 ConversionPatternRewriter &rewriter)
const override {
3304 rewriter.replaceOpWithNewOp<sim::QueueConcatOp>(
3305 op, getTypeConverter()->convertType(op.getResult().getType()),
3306 adaptor.getInputs());
3311struct AssocArrayExtractOpConversion
3313 using OpConversionPattern::OpConversionPattern;
3315 matchAndRewrite(AssocArrayExtractOp op, OpAdaptor adaptor,
3316 ConversionPatternRewriter &rewriter)
const override {
3317 Type resultType = getTypeConverter()->convertType(op.getResult().getType());
3325 sim::AssocArrayGetOp::create(rewriter, op.getLoc(), resultType,
3326 adaptor.getInput(), adaptor.getIndex());
3327 Value exists = sim::AssocArrayExistsOp::create(
3328 rewriter, op.getLoc(), adaptor.getInput(), adaptor.getIndex());
3330 Value existsBit = comb::ICmpOp::create(
3331 rewriter, op.getLoc(), comb::ICmpPredicate::ne, exists, zeroI32,
false);
3332 rewriter.replaceOpWithNewOp<comb::MuxOp>(op, existsBit, raw, zero,
false);
3338 using OpConversionPattern::OpConversionPattern;
3340 matchAndRewrite(UArrayCmpOp op, OpAdaptor adaptor,
3341 ConversionPatternRewriter &rewriter)
const override {
3342 Value lhs = adaptor.getLhs();
3343 Value rhs = adaptor.getRhs();
3344 auto pred = op.getPredicate();
3345 Value eq = buildUArrayElementEq(rewriter, op.getLoc(), lhs, rhs,
3346 lhs.getType(), pred);
3349 return rewriter.notifyMatchFailure(
3350 op,
"unpacked array element type does not support comparison");
3352 rewriter.replaceOp(op, eq);
3358 using OpConversionPattern::OpConversionPattern;
3360 matchAndRewrite(AssocArraySetOp op, OpAdaptor adaptor,
3361 ConversionPatternRewriter &rewriter)
const override {
3362 probeRefAndAssignResult(
3363 rewriter, op.getLoc(), adaptor.getAssocArray(), [&](Value array) {
3364 return sim::AssocArraySetOp::create(rewriter, op.getLoc(), array,
3369 rewriter.eraseOp(op);
3374struct AssocArrayDeleteOpConversion
3376 using OpConversionPattern::OpConversionPattern;
3378 matchAndRewrite(AssocArrayDeleteOp op, OpAdaptor adaptor,
3379 ConversionPatternRewriter &rewriter)
const override {
3380 probeRefAndAssignResult(
3381 rewriter, op.getLoc(), adaptor.getAssocArray(), [&](Value array) {
3382 return sim::AssocArrayDeleteOp::create(rewriter, op.getLoc(), array,
3386 rewriter.eraseOp(op);
3391struct AssocArrayClearOpConversion
3393 using OpConversionPattern::OpConversionPattern;
3395 matchAndRewrite(AssocArrayClearOp op, OpAdaptor adaptor,
3396 ConversionPatternRewriter &rewriter)
const override {
3397 auto refType = cast<llhd::RefType>(adaptor.getAssocArray().getType());
3398 Value emptyArray = sim::AssocArrayEmptyOp::create(rewriter, op->getLoc(),
3399 refType.getNestedType());
3400 llhd::AssignOp::create(rewriter, op.getLoc(), adaptor.getAssocArray(),
3401 emptyArray, Value{});
3402 rewriter.eraseOp(op);
3407struct AssocArraySizeOpConversion
3409 using OpConversionPattern::OpConversionPattern;
3411 matchAndRewrite(AssocArraySizeOp op, OpAdaptor adaptor,
3412 ConversionPatternRewriter &rewriter)
const override {
3414 llhd::ProbeOp::create(rewriter, op.getLoc(), adaptor.getAssocArray());
3415 rewriter.replaceOpWithNewOp<sim::AssocArraySizeOp>(op, array);
3420struct AssocArrayExistsOpConversion
3422 using OpConversionPattern::OpConversionPattern;
3424 matchAndRewrite(AssocArrayExistsOp op, OpAdaptor adaptor,
3425 ConversionPatternRewriter &rewriter)
const override {
3427 llhd::ProbeOp::create(rewriter, op.getLoc(), adaptor.getAssocArray());
3428 rewriter.replaceOpWithNewOp<sim::AssocArrayExistsOp>(op, array,
3429 adaptor.getIndex());
3434template <
typename MooreOpTy,
typename SimOpTy>
3436 using OpConversionPattern<MooreOpTy>::OpConversionPattern;
3437 using OpAdaptor =
typename MooreOpTy::Adaptor;
3439 matchAndRewrite(MooreOpTy op, OpAdaptor adaptor,
3440 ConversionPatternRewriter &rewriter)
const override {
3442 llhd::ProbeOp::create(rewriter, op.getLoc(), adaptor.getAssocArray());
3443 auto endpointOp = SimOpTy::create(rewriter, op.getLoc(), array);
3445 llhd::ProbeOp::create(rewriter, op.getLoc(), adaptor.getIndex());
3448 comb::ICmpOp::create(rewriter, op.getLoc(), comb::ICmpPredicate::ne,
3449 endpointOp->getResult(0), zero,
false);
3451 comb::MuxOp::create(rewriter, op.getLoc(), foundBit,
3452 endpointOp->getResult(1), curIndex,
false);
3453 llhd::AssignOp::create(rewriter, op.getLoc(), adaptor.getIndex(), newIndex,
3455 rewriter.replaceOp(op, endpointOp->getResult(0));
3460template <
typename MooreOpTy,
typename SimOpTy>
3462 using OpConversionPattern<MooreOpTy>::OpConversionPattern;
3463 using OpAdaptor =
typename MooreOpTy::Adaptor;
3465 matchAndRewrite(MooreOpTy op, OpAdaptor adaptor,
3466 ConversionPatternRewriter &rewriter)
const override {
3468 llhd::ProbeOp::create(rewriter, op.getLoc(), adaptor.getAssocArray());
3470 llhd::ProbeOp::create(rewriter, op.getLoc(), adaptor.getIndex());
3471 auto stepOp = SimOpTy::create(rewriter, op.getLoc(), array, curIndex);
3472 llhd::AssignOp::create(rewriter, op.getLoc(), adaptor.getIndex(),
3473 stepOp->getResult(1), Value{});
3474 rewriter.replaceOp(op, stepOp->getResult(0));
3479using AssocArrayFirstOpConversion =
3480 AssocArrayEndpointOpConversion<AssocArrayFirstOp, sim::AssocArrayFirstOp>;
3481using AssocArrayLastOpConversion =
3482 AssocArrayEndpointOpConversion<AssocArrayLastOp, sim::AssocArrayLastOp>;
3483using AssocArrayNextOpConversion =
3484 AssocArrayStepOpConversion<AssocArrayNextOp, sim::AssocArrayNextOp>;
3485using AssocArrayPrevOpConversion =
3486 AssocArrayStepOpConversion<AssocArrayPrevOp, sim::AssocArrayPrevOp>;
3489 using OpConversionPattern::OpConversionPattern;
3492 matchAndRewrite(DisplayBIOp op, OpAdaptor adaptor,
3493 ConversionPatternRewriter &rewriter)
const override {
3494 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(
3495 op, adaptor.getMessage());
3501 using OpConversionPattern::OpConversionPattern;
3503 matchAndRewrite(FDisplayBIOp op, OpAdaptor adaptor,
3504 ConversionPatternRewriter &rewriter)
const override {
3505 auto stream = sim::SVChannelToOutputStreamOp::create(rewriter, op.getLoc(),
3507 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(
3508 op, adaptor.getMessage(), stream.getStream());
3514 using OpConversionPattern::OpConversionPattern;
3516 matchAndRewrite(FOpenBIOp op, OpAdaptor adaptor,
3517 ConversionPatternRewriter &rewriter)
const override {
3518 sim::SVFOpenModeAttr simMode;
3519 if (
auto modeAttr = op.getModeAttr()) {
3520 auto mapMode = [](moore::FOpenMode m) -> sim::SVFOpenMode {
3522 case moore::FOpenMode::Read:
3523 return sim::SVFOpenMode::Read;
3524 case moore::FOpenMode::Write:
3525 return sim::SVFOpenMode::Write;
3526 case moore::FOpenMode::Append:
3527 return sim::SVFOpenMode::Append;
3528 case moore::FOpenMode::ReadUpdate:
3529 return sim::SVFOpenMode::ReadUpdate;
3530 case moore::FOpenMode::WriteUpdate:
3531 return sim::SVFOpenMode::WriteUpdate;
3532 case moore::FOpenMode::AppendUpdate:
3533 return sim::SVFOpenMode::AppendUpdate;
3535 llvm_unreachable(
"unknown FOpenMode");
3537 simMode = sim::SVFOpenModeAttr::get(op.getContext(),
3538 mapMode(modeAttr.getValue()));
3540 rewriter.replaceOpWithNewOp<sim::SVFOpenOp>(op, adaptor.getFilename(),
3546struct PlusArgsTestBIOpConversion
3548 using OpConversionPattern::OpConversionPattern;
3550 matchAndRewrite(PlusArgsTestBIOp op, OpAdaptor adaptor,
3551 ConversionPatternRewriter &rewriter)
const override {
3552 rewriter.replaceOpWithNewOp<sim::PlusArgsTestOp>(op, rewriter.getI1Type(),
3553 op.getFormatStringAttr());
3558struct PlusArgsValueBIOpConversion
3560 using OpConversionPattern::OpConversionPattern;
3562 matchAndRewrite(PlusArgsValueBIOp op, OpAdaptor adaptor,
3563 ConversionPatternRewriter &rewriter)
const override {
3564 auto resultType = typeConverter->convertType(op.getResult().getType());
3566 return rewriter.notifyMatchFailure(op,
"unsupported result type");
3567 rewriter.replaceOpWithNewOp<sim::PlusArgsValueOp>(
3568 op, rewriter.getI1Type(), resultType, op.getFormatStringAttr());
3574 using OpConversionPattern::OpConversionPattern;
3577 matchAndRewrite(FCloseBIOp op, OpAdaptor adaptor,
3578 ConversionPatternRewriter &rewriter)
const override {
3579 rewriter.replaceOpWithNewOp<sim::SVFCloseOp>(op, adaptor.getFd());
3585 using OpConversionPattern::OpConversionPattern;
3588 matchAndRewrite(FFlushBIOp op, OpAdaptor adaptor,
3589 ConversionPatternRewriter &rewriter)
const override {
3590 if (!adaptor.getFd()) {
3591 rewriter.replaceOpWithNewOp<sim::SVFFlushAllOp>(op);
3593 auto stream = sim::SVChannelToOutputStreamOp::create(
3594 rewriter, op.getLoc(), adaptor.getFd());
3595 rewriter.replaceOpWithNewOp<sim::FlushOp>(op, stream);
3602 using OpConversionPattern::OpConversionPattern;
3605 matchAndRewrite(StringCmpOp op, OpAdaptor adaptor,
3606 ConversionPatternRewriter &rewriter)
const override {
3607 sim::StringCmpPredicate pred;
3608 switch (op.getPredicate()) {
3609 case moore::StringCmpPredicate::eq:
3610 pred = sim::StringCmpPredicate::eq;
3612 case moore::StringCmpPredicate::ne:
3613 pred = sim::StringCmpPredicate::ne;
3615 case moore::StringCmpPredicate::lt:
3616 pred = sim::StringCmpPredicate::lt;
3618 case moore::StringCmpPredicate::le:
3619 pred = sim::StringCmpPredicate::le;
3621 case moore::StringCmpPredicate::gt:
3622 pred = sim::StringCmpPredicate::gt;
3624 case moore::StringCmpPredicate::ge:
3625 pred = sim::StringCmpPredicate::ge;
3628 rewriter.replaceOpWithNewOp<sim::StringCmpOp>(op, pred, adaptor.getLhs(),
3635 using OpConversionPattern::OpConversionPattern;
3638 matchAndRewrite(StringCompareOp op, OpAdaptor adaptor,
3639 ConversionPatternRewriter &rewriter)
const override {
3640 rewriter.replaceOpWithNewOp<sim::StringCompareOp>(op, adaptor.getLhs(),
3646struct StringICompareOpConversion
3648 using OpConversionPattern::OpConversionPattern;
3651 matchAndRewrite(StringICompareOp op, OpAdaptor adaptor,
3652 ConversionPatternRewriter &rewriter)
const override {
3653 Location loc = op.getLoc();
3655 sim::StringToLowerOp::create(rewriter, loc, adaptor.getLhs());
3657 sim::StringToLowerOp::create(rewriter, loc, adaptor.getRhs());
3658 rewriter.replaceOpWithNewOp<sim::StringCompareOp>(op, lowerLhs, lowerRhs);
3664 using OpConversionPattern::OpConversionPattern;
3667 matchAndRewrite(StringToLowerOp op, OpAdaptor adaptor,
3668 ConversionPatternRewriter &rewriter)
const override {
3669 rewriter.replaceOpWithNewOp<sim::StringToLowerOp>(op, adaptor.getStr());
3675 using OpConversionPattern::OpConversionPattern;
3678 matchAndRewrite(StringToUpperOp op, OpAdaptor adaptor,
3679 ConversionPatternRewriter &rewriter)
const override {
3680 rewriter.replaceOpWithNewOp<sim::StringToUpperOp>(op, adaptor.getStr());
3686 using OpConversionPattern::OpConversionPattern;
3689 matchAndRewrite(StringSubstrOp op, OpAdaptor adaptor,
3690 ConversionPatternRewriter &rewriter)
const override {
3691 Location loc = op.getLoc();
3692 Value str = adaptor.getStr();
3693 Value start = adaptor.getStart();
3694 Value
end = adaptor.getEnd();
3698 Value len = sim::StringLengthOp::create(rewriter, loc, str);
3700 Value startGeZero = arith::CmpIOp::create(
3701 rewriter, loc, arith::CmpIPredicate::sge, start, zero);
3702 Value endGeStart = arith::CmpIOp::create(
3703 rewriter, loc, arith::CmpIPredicate::sge, end, start);
3704 Value endLeLen = arith::CmpIOp::create(rewriter, loc,
3705 arith::CmpIPredicate::sle, end, len);
3707 Value isWithinBounds = arith::AndIOp::create(
3708 rewriter, loc, endLeLen,
3709 arith::AndIOp::create(rewriter, loc, startGeZero, endGeStart));
3711 Value subStr = sim::StringSubstrOp::create(
3712 rewriter, loc, str, adaptor.getStart(), adaptor.getEnd());
3714 rewriter.replaceOpWithNewOp<arith::SelectOp>(op, isWithinBounds, subStr,
3722 using OpConversionPattern::OpConversionPattern;
3725 matchAndRewrite(ReadMemBIOp op, OpAdaptor adaptor,
3726 ConversionPatternRewriter &rewriter)
const override {
3727 auto loc = op.getLoc();
3728 Value memory = llhd::ProbeOp::create(rewriter, loc, adaptor.getDest());
3729 Value loaded = sim::SVReadMemOp::create(
3730 rewriter, loc, memory.getType(), adaptor.getFilename(), memory,
3731 rewriter.getBoolAttr(op.getBase() == MemBase::Binary),
3732 adaptor.getStartAddr(), adaptor.getFinishAddr(), adaptor.getSliceLeft(),
3733 adaptor.getSliceRight(), op.getDimLowsAttr(), op.getDimDescendingAttr(),
3734 op.getEnumValuesAttr());
3735 rewriter.replaceOpWithNewOp<llhd::AssignOp>(op, adaptor.getDest(), loaded,
3748static LogicalResult
convert(StopBIOp op, StopBIOp::Adaptor adaptor,
3749 ConversionPatternRewriter &rewriter) {
3750 rewriter.replaceOpWithNewOp<sim::PauseOp>(op,
false);
3755static LogicalResult
convert(FinishBIOp op, FinishBIOp::Adaptor adaptor,
3756 ConversionPatternRewriter &rewriter) {
3757 rewriter.replaceOpWithNewOp<sim::TerminateOp>(op, op.getExitCode() == 0,
3763static LogicalResult
convert(SeverityBIOp op, SeverityBIOp::Adaptor adaptor,
3764 ConversionPatternRewriter &rewriter) {
3766 std::string severityString;
3768 switch (op.getSeverity()) {
3769 case (Severity::Fatal):
3770 severityString =
"Fatal: ";
3772 case (Severity::Error):
3773 severityString =
"Error: ";
3775 case (Severity::Warning):
3776 severityString =
"Warning: ";
3778 case (Severity::Info):
3779 severityString =
"Info: ";
3784 sim::FormatLiteralOp::create(rewriter, op.getLoc(), severityString);
3785 auto message = sim::FormatStringConcatOp::create(
3786 rewriter, op.getLoc(), ValueRange{prefix, adaptor.getMessage()});
3787 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(op, message);
3801 UrandomRangeBIOp::Adaptor adaptor,
3802 ConversionPatternRewriter &rewriter,
3803 FunctionCache &funcCache) {
3804 auto loc = op.getLoc();
3805 auto i32Ty = rewriter.getI32Type();
3806 auto ptrTy = LLVM::LLVMPointerType::get(rewriter.getContext());
3807 auto fn = funcCache.getOrCreate(rewriter,
"__circt_urandom_range",
3808 {i32Ty, i32Ty, ptrTy}, {i32Ty});
3811 if (
auto seedRef = adaptor.getSeed()) {
3814 seedPtr = LLVM::AllocaOp::create(rewriter, loc, ptrTy, i32Ty, one);
3815 auto seedVal = llhd::ProbeOp::create(rewriter, loc, seedRef);
3816 LLVM::StoreOp::create(rewriter, loc, seedVal, seedPtr);
3818 seedPtr = LLVM::ZeroOp::create(rewriter, loc, ptrTy);
3821 auto call = func::CallOp::create(
3823 ValueRange{adaptor.getMinval(), adaptor.getMaxval(), seedPtr});
3826 if (adaptor.getSeed()) {
3827 auto newSeed = LLVM::LoadOp::create(rewriter, loc, i32Ty, seedPtr);
3828 llhd::AssignOp::create(rewriter, loc, adaptor.getSeed(), newSeed, Value{});
3831 rewriter.replaceOp(op, call.getResult(0));
3837 FinishMessageBIOp::Adaptor adaptor,
3838 ConversionPatternRewriter &rewriter) {
3840 rewriter.eraseOp(op);
3849static LogicalResult
convert(TimeBIOp op, TimeBIOp::Adaptor adaptor,
3850 ConversionPatternRewriter &rewriter) {
3851 rewriter.replaceOpWithNewOp<llhd::CurrentTimeOp>(op);
3856static LogicalResult
convert(LogicToTimeOp op, LogicToTimeOp::Adaptor adaptor,
3857 ConversionPatternRewriter &rewriter) {
3858 rewriter.replaceOpWithNewOp<llhd::IntToTimeOp>(op, adaptor.getInput());
3863static LogicalResult
convert(TimeToLogicOp op, TimeToLogicOp::Adaptor adaptor,
3864 ConversionPatternRewriter &rewriter) {
3865 rewriter.replaceOpWithNewOp<llhd::TimeToIntOp>(op, adaptor.getInput());
3874 const TypeConverter &converter) {
3875 target.addIllegalDialect<MooreDialect>();
3876 target.addLegalDialect<comb::CombDialect>();
3877 target.addLegalDialect<hw::HWDialect>();
3878 target.addLegalDialect<seq::SeqDialect>();
3879 target.addLegalDialect<llhd::LLHDDialect>();
3880 target.addLegalDialect<ltl::LTLDialect>();
3881 target.addLegalDialect<mlir::BuiltinDialect>();
3882 target.addLegalDialect<mlir::math::MathDialect>();
3883 target.addLegalDialect<sim::SimDialect>();
3884 target.addLegalDialect<mlir::LLVM::LLVMDialect>();
3885 target.addLegalDialect<mlir::ub::UBDialect>();
3886 target.addLegalDialect<verif::VerifDialect>();
3887 target.addLegalDialect<arith::ArithDialect>();
3889 target.addLegalOp<debug::ScopeOp>();
3891 target.addDynamicallyLegalOp<scf::YieldOp, func::CallOp, func::ReturnOp,
3892 UnrealizedConversionCastOp, hw::OutputOp,
3893 hw::InstanceOp, debug::ArrayOp, debug::StructOp,
3894 debug::VariableOp, arith::SelectOp>(
3895 [&](Operation *op) {
return converter.isLegal(op); });
3897 target.addDynamicallyLegalOp<scf::IfOp, scf::ForOp, scf::ExecuteRegionOp,
3898 scf::WhileOp, scf::ForallOp>([&](Operation *op) {
3899 return converter.isLegal(op) && !op->getParentOfType<llhd::ProcessOp>();
3902 target.addDynamicallyLegalOp<func::FuncOp>([&](func::FuncOp op) {
3903 return converter.isSignatureLegal(op.getFunctionType());
3907 return converter.isSignatureLegal(op.getModuleType().getFuncType()) &&
3908 converter.isLegal(&op.getBody());
3913 typeConverter.addConversion([&](IntType type) {
3914 return IntegerType::get(type.getContext(), type.getWidth());
3917 typeConverter.addConversion([&](RealType type) -> mlir::Type {
3918 MLIRContext *ctx = type.getContext();
3919 switch (type.getWidth()) {
3921 return mlir::Float32Type::get(ctx);
3923 return mlir::Float64Type::get(ctx);
3927 typeConverter.addConversion(
3928 [&](TimeType type) {
return llhd::TimeType::get(type.getContext()); });
3930 typeConverter.addConversion([&](FormatStringType type) {
3931 return sim::FormatStringType::get(type.getContext());
3934 typeConverter.addConversion([&](StringType type) {
3935 return sim::DynamicStringType::get(type.getContext());
3938 typeConverter.addConversion([&](QueueType type) {
3939 return sim::QueueType::get(type.getContext(),
3940 typeConverter.convertType(type.getElementType()),
3944 typeConverter.addConversion([&](sim::QueueType type) -> std::optional<Type> {
3945 if (
auto elementType = typeConverter.convertType(type.getElementType()))
3946 return sim::QueueType::get(type.getContext(),
elementType,
3951 typeConverter.addConversion([&](ArrayType type) -> std::optional<Type> {
3952 if (
auto elementType = typeConverter.convertType(type.getElementType()))
3953 return hw::ArrayType::get(
elementType, type.getSize());
3957 typeConverter.addConversion([&](AssocArrayType type) -> std::optional<Type> {
3958 auto elementType = typeConverter.convertType(type.getElementType());
3959 auto indexType = typeConverter.convertType(type.getIndexType());
3962 return sim::AssocArrayType::get(type.getContext(),
elementType, indexType);
3968 typeConverter.addConversion(
3969 [&](UnpackedArrayType type) -> std::optional<Type> {
3970 if (
auto elementType = typeConverter.convertType(type.getElementType()))
3971 return hw::ArrayType::get(
elementType, type.getSize());
3975 typeConverter.addConversion([&](OpenArrayType type) -> std::optional<Type> {
3976 return LLVM::LLVMPointerType::get(type.getContext());
3979 typeConverter.addConversion(
3980 [&](OpenUnpackedArrayType type) -> std::optional<Type> {
3981 return LLVM::LLVMPointerType::get(type.getContext());
3984 typeConverter.addConversion([&](StructType type) -> std::optional<Type> {
3985 SmallVector<hw::StructType::FieldInfo> fields;
3986 for (
auto field : type.getMembers()) {
3987 hw::StructType::FieldInfo info;
3988 info.type = typeConverter.convertType(field.type);
3991 info.name = field.name;
3992 fields.push_back(info);
3994 return hw::StructType::get(type.getContext(), fields);
4002 typeConverter.addConversion(
4003 [&](UnpackedStructType type) -> std::optional<Type> {
4004 SmallVector<hw::StructType::FieldInfo> fields;
4005 for (
auto field : type.getMembers()) {
4006 hw::StructType::FieldInfo info;
4007 info.type = typeConverter.convertType(field.type);
4010 info.name = field.name;
4011 fields.push_back(info);
4013 return hw::StructType::get(type.getContext(), fields);
4017 typeConverter.addConversion([&](UnionType type) -> std::optional<Type> {
4018 SmallVector<hw::UnionType::FieldInfo> fields;
4019 for (
auto field : type.getMembers()) {
4020 hw::UnionType::FieldInfo info;
4021 info.type = typeConverter.convertType(field.type);
4024 info.name = field.name;
4026 fields.push_back(info);
4028 auto result = hw::UnionType::get(type.getContext(), fields);
4033 typeConverter.addConversion(
4034 [&](UnpackedUnionType type) -> std::optional<Type> {
4035 SmallVector<hw::UnionType::FieldInfo> fields;
4036 for (
auto field : type.getMembers()) {
4037 hw::UnionType::FieldInfo info;
4038 info.type = typeConverter.convertType(field.type);
4041 info.name = field.name;
4043 fields.push_back(info);
4045 return hw::UnionType::get(type.getContext(), fields);
4049 typeConverter.addConversion([&](ChandleType type) -> std::optional<Type> {
4050 return LLVM::LLVMPointerType::get(type.getContext());
4054 typeConverter.addConversion(
4055 [](LLVM::LLVMPointerType t) -> std::optional<Type> {
return t; });
4058 typeConverter.addConversion([&](ClassHandleType type) -> std::optional<Type> {
4059 return LLVM::LLVMPointerType::get(type.getContext());
4063 typeConverter.addConversion([&](NullType type) -> std::optional<Type> {
4064 return LLVM::LLVMPointerType::get(type.getContext());
4067 typeConverter.addConversion([&](RefType type) -> std::optional<Type> {
4068 if (isa<OpenArrayType, OpenUnpackedArrayType>(type.getNestedType()))
4069 return LLVM::LLVMPointerType::get(type.getContext());
4070 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
4071 return llhd::RefType::get(innerType);
4075 typeConverter.addConversion([&](NetType type) -> std::optional<Type> {
4076 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
4077 return llhd::NetType::get(innerType);
4082 typeConverter.addConversion([](IntegerType type) {
return type; });
4083 typeConverter.addConversion([](FloatType type) {
return type; });
4084 typeConverter.addConversion([](sim::DynamicStringType type) {
return type; });
4085 typeConverter.addConversion([](sim::FormatStringType type) {
return type; });
4086 typeConverter.addConversion([](sim::AssocArrayType type) {
return type; });
4087 typeConverter.addConversion([](llhd::TimeType type) {
return type; });
4088 typeConverter.addConversion([](debug::ArrayType type) {
return type; });
4089 typeConverter.addConversion([](debug::ScopeType type) {
return type; });
4090 typeConverter.addConversion([](debug::StructType type) {
return type; });
4092 typeConverter.addConversion([&](llhd::RefType type) -> std::optional<Type> {
4093 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
4094 return llhd::RefType::get(innerType);
4098 typeConverter.addConversion([&](llhd::NetType type) -> std::optional<Type> {
4099 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
4100 return llhd::NetType::get(innerType);
4104 typeConverter.addConversion([&](hw::ArrayType type) -> std::optional<Type> {
4105 if (
auto elementType = typeConverter.convertType(type.getElementType()))
4106 return hw::ArrayType::get(
elementType, type.getNumElements());
4110 typeConverter.addConversion([&](hw::StructType type) -> std::optional<Type> {
4111 SmallVector<hw::StructType::FieldInfo> fields;
4112 for (
auto field : type.getElements()) {
4113 hw::StructType::FieldInfo info;
4114 info.type = typeConverter.convertType(field.type);
4117 info.name = field.name;
4118 fields.push_back(info);
4120 return hw::StructType::get(type.getContext(), fields);
4123 typeConverter.addConversion([&](hw::UnionType type) -> std::optional<Type> {
4124 SmallVector<hw::UnionType::FieldInfo> fields;
4125 for (
auto field : type.getElements()) {
4126 hw::UnionType::FieldInfo info;
4127 info.type = typeConverter.convertType(field.type);
4130 info.name = field.name;
4131 info.offset = field.offset;
4132 fields.push_back(info);
4134 return hw::UnionType::get(type.getContext(), fields);
4137 typeConverter.addTargetMaterialization(
4138 [&](mlir::OpBuilder &builder, mlir::Type resultType,
4139 mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
4140 if (inputs.size() != 1 || !inputs[0])
4142 return UnrealizedConversionCastOp::create(builder, loc, resultType,
4147 typeConverter.addSourceMaterialization(
4148 [&](mlir::OpBuilder &builder, mlir::Type resultType,
4149 mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
4150 if (inputs.size() != 1)
4152 return UnrealizedConversionCastOp::create(builder, loc, resultType,
4159 TypeConverter &typeConverter,
4160 ClassTypeCache &classCache,
4161 FunctionCache &funcCache) {
4166 classCache, funcCache);
4167 patterns.add<ClassPropertyRefOpConversion>(typeConverter,
4168 patterns.getContext(), classCache);
4172 ClassUpcastOpConversion,
4173 NullOpConversion<NullOp>,
4174 NullOpConversion<NullChandleOp>,
4175 NullOpConversion<NullClassOp>,
4177 VariableOpConversion,
4181 BitcastConversion<PackedToSBVOp>,
4182 BitcastConversion<SBVToPackedOp>,
4183 NoOpConversion<LogicToIntOp>,
4184 NoOpConversion<IntToLogicOp>,
4185 NoOpConversion<ToBuiltinIntOp>,
4186 NoOpConversion<FromBuiltinIntOp>,
4190 SIntToRealOpConversion,
4191 UIntToRealOpConversion,
4192 IntToStringOpConversion,
4193 StringToIntOpConversion,
4194 FormatStringToStringOpConversion,
4195 RealToIntOpConversion,
4196 ConvertRealOpConversion,
4197 RealBitcastOpConversion<RealtobitsBIOp>,
4198 RealBitcastOpConversion<BitstorealBIOp>,
4199 RealBitcastOpConversion<ShortrealtobitsBIOp>,
4200 RealBitcastOpConversion<BitstoshortrealBIOp>,
4206 ReplicateOpConversion,
4208 ExtractOpConversion,
4209 DynExtractOpConversion,
4210 DynExtractRefOpConversion,
4212 StructExtractOpConversion,
4213 StructExtractRefOpConversion,
4214 ExtractRefOpConversion,
4215 StructCreateOpConversion,
4216 UnionCreateOpConversion,
4217 UnionExtractOpConversion,
4218 UnionExtractRefOpConversion,
4219 ConditionalOpConversion,
4220 ArrayCreateOpConversion,
4221 UArrayCmpOpConversion,
4224 ConstantStringOpConv,
4227 ReduceAndOpConversion,
4228 ReduceOrOpConversion,
4229 ReduceXorOpConversion,
4230 BoolCastOpConversion,
4235 BinaryOpConversion<AddOp, comb::AddOp>,
4236 BinaryOpConversion<SubOp, comb::SubOp>,
4237 BinaryOpConversion<MulOp, comb::MulOp>,
4238 BinaryOpConversion<DivUOp, comb::DivUOp>,
4239 BinaryOpConversion<DivSOp, comb::DivSOp>,
4240 BinaryOpConversion<ModUOp, comb::ModUOp>,
4241 BinaryOpConversion<ModSOp, comb::ModSOp>,
4242 BinaryOpConversion<AndOp, comb::AndOp>,
4243 BinaryOpConversion<OrOp, comb::OrOp>,
4244 BinaryOpConversion<XorOp, comb::XorOp>,
4247 NegRealOpConversion,
4250 BinaryRealOpConversion<AddRealOp, arith::AddFOp>,
4251 BinaryRealOpConversion<SubRealOp, arith::SubFOp>,
4252 BinaryRealOpConversion<DivRealOp, arith::DivFOp>,
4253 BinaryRealOpConversion<MulRealOp, arith::MulFOp>,
4254 BinaryRealOpConversion<PowRealOp, math::PowFOp>,
4257 RealMathFunc<LnBIOp, math::LogOp>,
4258 RealMathFunc<Log10BIOp, math::Log10Op>,
4259 RealMathFunc<ExpBIOp, math::ExpOp>,
4260 RealMathFunc<SqrtBIOp, math::SqrtOp>,
4261 BinaryRealOpConversion<MinBIOp, arith::MinimumFOp>,
4262 BinaryRealOpConversion<MaxBIOp, arith::MaximumFOp>,
4263 RealMathFunc<AbsBIOp, math::AbsFOp>,
4264 RealMathFunc<FloorBIOp, math::FloorOp>,
4265 RealMathFunc<CeilBIOp, math::CeilOp>,
4266 RealMathFunc<SinBIOp, math::SinOp>,
4267 RealMathFunc<CosBIOp, math::CosOp>,
4268 RealMathFunc<TanBIOp, math::TanOp>,
4269 RealMathFunc<AsinBIOp, math::AsinOp>,
4270 RealMathFunc<AcosBIOp, math::AcosOp>,
4271 RealMathFunc<AtanBIOp, math::AtanOp>,
4272 BinaryRealOpConversion<Atan2BIOp, math::Atan2Op>,
4273 HypotBIOpConversion,
4274 RealMathFunc<SinhBIOp, math::SinhOp>,
4275 RealMathFunc<CoshBIOp, math::CoshOp>,
4276 RealMathFunc<TanhBIOp, math::TanhOp>,
4277 RealMathFunc<AsinhBIOp, math::AsinhOp>,
4278 RealMathFunc<AcoshBIOp, math::AcoshOp>,
4279 RealMathFunc<AtanhBIOp, math::AtanhOp>,
4282 PowUOpConversion, PowSOpConversion,
4283 Clog2BIOpConversion,
4286 ICmpOpConversion<UltOp, ICmpPredicate::ult>,
4287 ICmpOpConversion<SltOp, ICmpPredicate::slt>,
4288 ICmpOpConversion<UleOp, ICmpPredicate::ule>,
4289 ICmpOpConversion<SleOp, ICmpPredicate::sle>,
4290 ICmpOpConversion<UgtOp, ICmpPredicate::ugt>,
4291 ICmpOpConversion<SgtOp, ICmpPredicate::sgt>,
4292 ICmpOpConversion<UgeOp, ICmpPredicate::uge>,
4293 ICmpOpConversion<SgeOp, ICmpPredicate::sge>,
4294 ICmpOpConversion<EqOp, ICmpPredicate::eq>,
4295 ICmpOpConversion<NeOp, ICmpPredicate::ne>,
4296 CaseEqOpConversion<CaseEqOp, ICmpPredicate::ceq, false>,
4297 CaseEqOpConversion<CaseNeOp, ICmpPredicate::cne, true>,
4298 WildcardEqOpConversion<WildcardEqOp, ICmpPredicate::weq, false>,
4299 WildcardEqOpConversion<WildcardNeOp, ICmpPredicate::wne, true>,
4300 FCmpOpConversion<NeRealOp, arith::CmpFPredicate::UNE>,
4301 FCmpOpConversion<FltOp, arith::CmpFPredicate::OLT>,
4302 FCmpOpConversion<FleOp, arith::CmpFPredicate::OLE>,
4303 FCmpOpConversion<FgtOp, arith::CmpFPredicate::OGT>,
4304 FCmpOpConversion<FgeOp, arith::CmpFPredicate::OGE>,
4305 FCmpOpConversion<EqRealOp, arith::CmpFPredicate::OEQ>,
4306 CaseXZEqOpConversion<CaseZEqOp, true>,
4307 CaseXZEqOpConversion<CaseXZEqOp, false>,
4308 HandleCmpOpConversion<HandleEqOp, LLVM::ICmpPredicate::eq>,
4309 HandleCmpOpConversion<HandleNeOp, LLVM::ICmpPredicate::ne>,
4312 SVModuleOpConversion,
4313 InstanceOpConversion,
4314 ProcedureOpConversion,
4315 CoroutineOpConversion,
4316 CallCoroutineOpConversion,
4317 WaitEventOpConversion,
4318 WaitLevelOpConversion,
4326 AssignOpConversion<ContinuousAssignOp>,
4327 AssignOpConversion<DelayedContinuousAssignOp>,
4328 AssignOpConversion<BlockingAssignOp>,
4329 AssignOpConversion<NonBlockingAssignOp>,
4330 AssignOpConversion<DelayedNonBlockingAssignOp>,
4331 AssignedVariableOpConversion,
4334 HWInstanceOpConversion,
4337 DPIFuncOpConversion,
4338 FuncDPICallOpConversion,
4339 UnrealizedConversionCastConversion,
4340 InPlaceOpConversion<debug::ArrayOp>,
4341 InPlaceOpConversion<debug::StructOp>,
4342 InPlaceOpConversion<debug::VariableOp>,
4345 AssertLikeOpConversion<AssertOp, verif::AssertOp>,
4346 AssertLikeOpConversion<AssumeOp, verif::AssumeOp>,
4347 AssertLikeOpConversion<CoverOp, verif::CoverOp>,
4350 FormatLiteralOpConversion,
4351 FormatStringOpConversion,
4352 FormatConcatOpConversion,
4353 FormatHierPathOpConversion,
4354 FormatIntOpConversion,
4355 FormatRealOpConversion,
4356 FormatCharOpConversion,
4357 DisplayBIOpConversion,
4358 FDisplayBIOpConversion,
4361 FOpenBIOpConversion,
4362 FCloseBIOpConversion,
4363 FFlushBIOpConversion,
4364 ReadMemBIOpConversion,
4367 PlusArgsTestBIOpConversion,
4368 PlusArgsValueBIOpConversion,
4371 StringLenOpConversion,
4372 StringConcatOpConversion,
4373 StringGetOpConversion,
4374 StringCmpOpConversion,
4375 StringCompareOpConversion,
4376 StringICompareOpConversion,
4377 StringToLowerOpConversion,
4378 StringToUpperOpConversion,
4379 StringSubstrOpConversion,
4382 QueueSizeBIOpConversion,
4383 QueuePushBackOpConversion,
4384 QueuePushFrontOpConversion,
4385 QueuePopBackOpConversion,
4386 QueuePopFrontOpConversion,
4387 QueueDeleteOpConversion,
4388 QueueInsertOpConversion,
4389 QueueClearOpConversion,
4390 DynQueueExtractOpConversion,
4391 QueueResizeOpConversion,
4392 QueueSetOpConversion,
4393 QueueCmpOpConversion,
4394 QueueFromUnpackedArrayOpConversion,
4395 QueueConcatOpConversion,
4398 AssocArrayExtractOpConversion,
4399 AssocArraySetOpConversion,
4400 AssocArrayDeleteOpConversion,
4401 AssocArrayClearOpConversion,
4402 AssocArraySizeOpConversion,
4403 AssocArrayExistsOpConversion,
4404 AssocArrayFirstOpConversion,
4405 AssocArrayLastOpConversion,
4406 AssocArrayNextOpConversion,
4407 AssocArrayPrevOpConversion
4408 >(typeConverter,
patterns.getContext());
4431 mlir::populateAnyFunctionOpInterfaceTypeConversionPattern(
patterns,
4434 hw::HWModuleOp::getOperationName(),
patterns, typeConverter);
4435 populateSCFToControlFlowConversionPatterns(
patterns);
4444struct MooreToCorePass
4445 :
public circt::impl::ConvertMooreToCoreBase<MooreToCorePass> {
4446 void runOnOperation()
override;
4452 return std::make_unique<MooreToCorePass>();
4456void MooreToCorePass::runOnOperation() {
4457 MLIRContext &
context = getContext();
4458 ModuleOp module = getOperation();
4459 ClassTypeCache classCache;
4460 auto &symbolTable = getAnalysis<SymbolTable>();
4461 FunctionCache funcCache(symbolTable);
4463 IRRewriter rewriter(module);
4464 (void)mlir::eraseUnreachableBlocks(rewriter, module->getRegions());
4466 TypeConverter typeConverter;
4474 mlir::cf::populateCFStructuralTypeConversionsAndLegality(typeConverter,
4477 if (failed(applyFullConversion(module, target, std::move(
patterns))))
4478 signalPassFailure();
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static Value createZeroValue(ImplicitLocOpBuilder &builder, FIRRTLBaseType type, SmallDenseMap< FIRRTLBaseType, Value > &cache)
Construct a zero value of the given type using the given builder.
static void populateLegality(ConversionTarget &target)
static void populateOpConversion(RewritePatternSet &patterns, TypeConverter &typeConverter)
static void populateTypeConversion(TypeConverter &converter)
static LogicalResult convert(arc::ExecuteOp op, arc::ExecuteOp::Adaptor adaptor, ConversionPatternRewriter &rewriter, const TypeConverter &converter)
false return failure()
Parse an optional keyword or string and set instance into 'result'.
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...
create(elements, Type result_type=None)
create(elements, Type result_type=None)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
bool isHWValueType(mlir::Type type)
Return true if the specified type can be used as an HW value type, that is the set of types that can ...
void populateHWModuleLikeTypeConversionPattern(StringRef moduleLikeOpName, RewritePatternSet &patterns, TypeConverter &converter)
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
@ f32
A standard 32-Bit floating point number ("float").
@ f64
A 64-bit double-precision floation point number ("double").
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.