21#include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h"
22#include "mlir/Dialect/Arith/IR/Arith.h"
23#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
24#include "mlir/Dialect/ControlFlow/Transforms/StructuralTypeConversions.h"
25#include "mlir/Dialect/Func/IR/FuncOps.h"
26#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
27#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
28#include "mlir/Dialect/Math/IR/Math.h"
29#include "mlir/Dialect/SCF/IR/SCF.h"
30#include "mlir/IR/BuiltinDialect.h"
31#include "mlir/IR/Iterators.h"
32#include "mlir/Interfaces/SideEffectInterfaces.h"
33#include "mlir/Pass/Pass.h"
34#include "mlir/Transforms/DialectConversion.h"
35#include "mlir/Transforms/RegionUtils.h"
36#include "llvm/ADT/TypeSwitch.h"
37#include "llvm/IR/DerivedTypes.h"
40#define GEN_PASS_DEF_CONVERTMOORETOCORE
41#include "circt/Conversion/Passes.h.inc"
48using comb::ICmpPredicate;
49using llvm::SmallDenseSet;
54struct ClassTypeCache {
56 LLVM::GlobalOp global;
59 struct ClassStructInfo {
60 LLVM::LLVMStructType classBody;
61 LLVM::LLVMStructType headerTy;
62 TypeInfoInfo typeInfo;
64 unsigned headerFieldIndex = 0;
65 unsigned typeInfoFieldIndex = 0;
66 unsigned vtableFieldIndex = 1;
69 DenseMap<StringRef, SmallVector<unsigned, 2>> propertyPath;
73 void setFieldPath(StringRef propertyName, ArrayRef<unsigned> path) {
74 this->propertyPath[propertyName] =
75 SmallVector<unsigned, 2>(path.begin(), path.end());
79 std::optional<ArrayRef<unsigned>>
80 getFieldPath(StringRef propertySym)
const {
81 if (
auto prop = this->propertyPath.find(propertySym);
82 prop != this->propertyPath.end())
83 return ArrayRef<unsigned>(prop->second);
90 void setClassInfo(SymbolRefAttr classSym,
const ClassStructInfo &
info) {
91 auto &dst = classToStructMap[classSym];
96 std::optional<ClassStructInfo> getStructInfo(SymbolRefAttr classSym)
const {
97 if (
auto it = classToStructMap.find(classSym); it != classToStructMap.end())
102 std::optional<TypeInfoInfo> getTypeInfo(SymbolRefAttr classSym)
const {
103 if (
auto it = classToTypeInfoMap.find(classSym);
104 it != classToTypeInfoMap.end())
109 void setTypeInfo(SymbolRefAttr classSym,
const TypeInfoInfo &
info) {
110 classToTypeInfoMap[classSym] =
info;
117 DenseMap<Attribute, ClassStructInfo> classToStructMap;
118 DenseMap<Attribute, TypeInfoInfo> classToTypeInfoMap;
123struct FunctionCache {
124 FunctionCache(SymbolTable &symbolTable) : symbolTable(symbolTable) {}
130 func::FuncOp getOrCreate(OpBuilder &builder, StringRef name,
131 function_ref<func::FuncOp()> createFn) {
132 auto &slot = map[name];
135 if (
auto fn = symbolTable.lookup<func::FuncOp>(name))
137 auto mod = cast<ModuleOp>(symbolTable.getOp());
138 OpBuilder::InsertionGuard g(builder);
139 builder.setInsertionPointToStart(mod.getBody());
141 symbolTable.insert(slot);
147 func::FuncOp getOrCreate(OpBuilder &builder, StringRef name,
148 TypeRange argTypes, TypeRange resultTypes) {
149 return getOrCreate(builder, name, [&] {
150 auto mod = cast<ModuleOp>(symbolTable.getOp());
151 auto fnTy = builder.getFunctionType(argTypes, resultTypes);
152 auto fn = func::FuncOp::create(builder, mod.getLoc(), name, fnTy);
159 SymbolTable &symbolTable;
160 llvm::StringMap<func::FuncOp> map;
165static LLVM::LLVMStructType getOrCreateOpaqueStruct(MLIRContext *ctx,
166 SymbolRefAttr className) {
167 return LLVM::LLVMStructType::getIdentified(ctx, className.getRootReference());
171static LLVM::LLVMStructType getClassObjectHeaderType(MLIRContext *ctx) {
172 return LLVM::LLVMStructType::getLiteral(
173 ctx, SmallVector<Type>{LLVM::LLVMPointerType::get(ctx),
174 LLVM::LLVMPointerType::get(ctx)});
177static std::string getTypeInfoName(SymbolRefAttr className) {
178 return className.getRootReference().str() +
"::typeinfo";
181static FailureOr<ClassTypeCache::TypeInfoInfo>
182getOrCreateTypeInfo(ModuleOp mod, SymbolRefAttr classSym,
183 ClassTypeCache &cache) {
184 if (
auto info = cache.getTypeInfo(classSym))
187 MLIRContext *ctx = mod.getContext();
188 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
189 auto typeInfoTy = LLVM::LLVMStructType::getLiteral(ctx, {ptrTy});
191 auto globalName = getTypeInfoName(classSym);
192 auto global = mod.lookupSymbol<LLVM::GlobalOp>(globalName);
194 OpBuilder builder = OpBuilder::atBlockBegin(mod.getBody());
195 global = LLVM::GlobalOp::create(
196 builder, mod.getLoc(), typeInfoTy,
197 true, LLVM::Linkage::Internal, globalName, Attribute());
200 global.getInitializerRegion().push_back(block);
201 builder.setInsertionPointToStart(block);
203 if (
auto *classOp = mod.lookupSymbol(classSym)) {
204 auto classDecl = dyn_cast<ClassDeclOp>(classOp);
205 if (classDecl && classDecl.getBaseAttr()) {
207 getOrCreateTypeInfo(mod, classDecl.getBaseAttr(), cache);
208 if (failed(baseInfo))
211 LLVM::AddressOfOp::create(builder, mod.getLoc(), baseInfo->global);
212 auto undef = LLVM::UndefOp::create(builder, mod.getLoc(), typeInfoTy)
214 auto init = LLVM::InsertValueOp::create(builder, mod.getLoc(), undef,
215 baseAddr.getResult(),
216 ArrayRef<int64_t>{0});
217 LLVM::ReturnOp::create(builder, mod.getLoc(), init);
218 ClassTypeCache::TypeInfoInfo
info{global};
219 cache.setTypeInfo(classSym, info);
225 LLVM::UndefOp::create(builder, mod.getLoc(), typeInfoTy).getResult();
227 LLVM::ZeroOp::create(builder, mod.getLoc(), ptrTy).getResult();
228 auto init = LLVM::InsertValueOp::create(builder, mod.getLoc(), undef,
229 nullPtr, ArrayRef<int64_t>{0});
230 LLVM::ReturnOp::create(builder, mod.getLoc(), init);
233 ClassTypeCache::TypeInfoInfo
info{global};
234 cache.setTypeInfo(classSym, info);
237static LogicalResult resolveClassStructBody(ClassDeclOp op,
238 TypeConverter
const &typeConverter,
239 ClassTypeCache &cache) {
241 auto classSym = SymbolRefAttr::get(op.getSymNameAttr());
242 auto structInfo = cache.getStructInfo(classSym);
247 if (failed(getOrCreateTypeInfo(op->getParentOfType<ModuleOp>(), classSym,
249 return op.emitOpError() <<
"Failed to create RTTI for class";
252 ClassTypeCache::ClassStructInfo structBody;
253 SmallVector<Type> structBodyMembers;
254 structBody.headerTy = getClassObjectHeaderType(op.getContext());
255 structBody.typeInfo = *cache.getTypeInfo(classSym);
256 structBodyMembers.push_back(structBody.headerTy);
259 unsigned derivedStartIdx = 1;
261 if (
auto baseClass = op.getBaseAttr()) {
263 ModuleOp mod = op->getParentOfType<ModuleOp>();
264 auto *opSym = mod.lookupSymbol(baseClass);
265 auto classDeclOp = cast<ClassDeclOp>(opSym);
267 if (failed(resolveClassStructBody(classDeclOp, typeConverter, cache)))
271 auto baseClassStruct = cache.getStructInfo(baseClass);
272 structBodyMembers.push_back(baseClassStruct->classBody);
277 for (
auto &kv : baseClassStruct->propertyPath) {
278 SmallVector<unsigned, 2> path;
280 path.append(kv.second.begin(), kv.second.end());
281 structBody.setFieldPath(kv.first, path);
286 unsigned iterator = derivedStartIdx;
287 auto &block = op.getBody().front();
288 for (Operation &child : block) {
289 if (
auto prop = dyn_cast<ClassPropertyDeclOp>(child)) {
290 Type mooreTy = prop.getPropertyType();
291 Type llvmTy = typeConverter.convertType(mooreTy);
293 return prop.emitOpError()
294 <<
"failed to convert property type " << mooreTy;
296 structBodyMembers.push_back(llvmTy);
299 SmallVector<unsigned, 2> path{iterator};
300 structBody.setFieldPath(prop.getSymName(), path);
306 auto llvmStructTy = getOrCreateOpaqueStruct(op.getContext(), classSym);
308 if (!structBodyMembers.empty() &&
309 failed(llvmStructTy.setBody(structBodyMembers,
false)))
310 return op.emitOpError() <<
"Failed to set LLVM Struct body";
312 structBody.classBody = llvmStructTy;
313 cache.setClassInfo(classSym, structBody);
319static LogicalResult resolveClassStructBody(ModuleOp mod, SymbolRefAttr op,
320 TypeConverter
const &typeConverter,
321 ClassTypeCache &cache) {
322 auto classDeclOp = cast<ClassDeclOp>(*mod.lookupSymbol(op));
323 return resolveClassStructBody(classDeclOp, typeConverter, cache);
330static Value adjustIntegerWidth(OpBuilder &builder, Value value,
331 uint32_t targetWidth, Location loc) {
332 uint32_t intWidth = value.getType().getIntOrFloatBitWidth();
333 if (intWidth == targetWidth)
336 if (intWidth < targetWidth) {
338 builder, loc, builder.getIntegerType(targetWidth - intWidth), 0);
339 return comb::ConcatOp::create(builder, loc, ValueRange{zeroExt, value});
343 intWidth - targetWidth);
345 builder, loc, builder.getIntegerType(intWidth - targetWidth), 0);
346 Value isZero = comb::ICmpOp::create(builder, loc, comb::ICmpPredicate::eq, hi,
350 builder.getIntegerType(targetWidth), -1);
351 return comb::MuxOp::create(builder, loc, isZero, lo, max,
false);
355static FailureOr<hw::ModulePortInfo>
356getModulePortInfo(
const TypeConverter &typeConverter, SVModuleOp op) {
358 size_t resultNum = 0;
359 auto moduleTy = op.getModuleType();
360 SmallVector<hw::PortInfo> ports;
361 ports.reserve(moduleTy.getNumPorts());
363 for (
auto port : moduleTy.getPorts()) {
364 Type portTy = typeConverter.convertType(port.type);
366 return op.emitOpError(
"port '")
367 << port.name <<
"' has unsupported type " << port.type
368 <<
" that cannot be converted to hardware type";
370 if (port.dir == hw::ModulePort::Direction::Output) {
372 hw::PortInfo({{port.name, portTy, port.dir}, resultNum++, {}}));
380 hw::PortInfo({{port.name, portTy, port.dir}, inputNum++, {}}));
386struct DpiArrayCastInfo {
389 bool isPacked =
false;
393static std::optional<DpiArrayCastInfo> getDpiArrayCastInfo(Type type) {
394 DpiArrayCastInfo
info;
395 if (
auto refType = dyn_cast<RefType>(type)) {
397 type = refType.getNestedType();
400 if (
auto arrayType = dyn_cast<ArrayType>(type)) {
401 info.isPacked =
true;
402 info.elementType = arrayType.getElementType();
405 if (
auto arrayType = dyn_cast<OpenArrayType>(type)) {
407 info.isPacked =
true;
408 info.elementType = arrayType.getElementType();
411 if (
auto arrayType = dyn_cast<UnpackedArrayType>(type)) {
412 info.elementType = arrayType.getElementType();
415 if (
auto arrayType = dyn_cast<OpenUnpackedArrayType>(type)) {
417 info.elementType = arrayType.getElementType();
423static bool hasOpenArrayBoundaryType(Type type) {
424 if (isa<OpenArrayType, OpenUnpackedArrayType>(type))
426 if (
auto refType = dyn_cast<RefType>(type))
427 return isa<OpenArrayType, OpenUnpackedArrayType>(refType.getNestedType());
431static bool isSupportedDpiOpenArrayCast(Type source, Type target) {
432 auto sourceInfo = getDpiArrayCastInfo(source);
433 auto targetInfo = getDpiArrayCastInfo(target);
434 if (!sourceInfo || !targetInfo)
439 return sourceInfo->isRef == targetInfo->isRef &&
440 sourceInfo->isPacked == targetInfo->isPacked &&
441 sourceInfo->elementType == targetInfo->elementType &&
442 (targetInfo->isOpen && !sourceInfo->isOpen);
450 using OpConversionPattern::OpConversionPattern;
453 matchAndRewrite(SVModuleOp op, OpAdaptor adaptor,
454 ConversionPatternRewriter &rewriter)
const override {
455 rewriter.setInsertionPoint(op);
458 auto portInfo = getModulePortInfo(*typeConverter, op);
459 if (failed(portInfo))
462 auto hwModuleOp = hw::HWModuleOp::create(rewriter, op.getLoc(),
463 op.getSymNameAttr(), *portInfo);
466 SymbolTable::setSymbolVisibility(hwModuleOp,
467 SymbolTable::getSymbolVisibility(op));
468 rewriter.eraseBlock(hwModuleOp.getBodyBlock());
470 rewriter.convertRegionTypes(&op.getBodyRegion(), *typeConverter)))
472 rewriter.inlineRegionBefore(op.getBodyRegion(), hwModuleOp.getBodyRegion(),
473 hwModuleOp.getBodyRegion().end());
476 rewriter.eraseOp(op);
482 using OpConversionPattern::OpConversionPattern;
485 matchAndRewrite(OutputOp op, OpAdaptor adaptor,
486 ConversionPatternRewriter &rewriter)
const override {
487 rewriter.replaceOpWithNewOp<hw::OutputOp>(op, adaptor.getOperands());
493 using OpConversionPattern::OpConversionPattern;
496 matchAndRewrite(InstanceOp op, OpAdaptor adaptor,
497 ConversionPatternRewriter &rewriter)
const override {
498 auto instName = op.getInstanceNameAttr();
499 auto moduleName = op.getModuleNameAttr();
502 rewriter.setInsertionPoint(op);
503 auto instOp = hw::InstanceOp::create(
504 rewriter, op.getLoc(), op.getResultTypes(), instName, moduleName,
505 op.getInputs(), op.getInputNamesAttr(), op.getOutputNamesAttr(),
506 rewriter.getArrayAttr({}),
nullptr,
510 op.replaceAllUsesWith(instOp.getResults());
511 rewriter.eraseOp(op);
516static void getValuesToObserve(Region *region,
517 function_ref<
void(Value)> setInsertionPoint,
518 const TypeConverter *typeConverter,
519 ConversionPatternRewriter &rewriter,
520 SmallVector<Value> &observeValues) {
521 SmallDenseSet<Value> alreadyObserved;
522 Location loc = region->getLoc();
524 auto probeIfSignal = [&](Value value) -> Value {
525 if (!isa<llhd::RefType>(value.getType()))
527 return llhd::ProbeOp::create(rewriter, loc, value);
530 region->getParentOp()->walk<WalkOrder::PreOrder, ForwardDominanceIterator<>>(
531 [&](Operation *operation) {
532 for (
auto value : operation->getOperands()) {
533 if (isa<BlockArgument>(value))
534 value = rewriter.getRemappedValue(value);
536 if (region->isAncestor(value.getParentRegion()))
538 if (
auto *defOp = value.getDefiningOp();
539 defOp && defOp->hasTrait<OpTrait::ConstantLike>())
541 if (!alreadyObserved.insert(value).second)
544 OpBuilder::InsertionGuard g(rewriter);
545 if (
auto remapped = rewriter.getRemappedValue(value)) {
546 setInsertionPoint(remapped);
547 observeValues.push_back(probeIfSignal(remapped));
549 setInsertionPoint(value);
550 auto type = typeConverter->convertType(value.getType());
551 auto converted = typeConverter->materializeTargetConversion(
552 rewriter, loc, type, value);
553 observeValues.push_back(probeIfSignal(converted));
560 using OpConversionPattern::OpConversionPattern;
563 matchAndRewrite(ProcedureOp op, OpAdaptor adaptor,
564 ConversionPatternRewriter &rewriter)
const override {
566 SmallVector<Value> observedValues;
567 if (op.getKind() == ProcedureKind::AlwaysComb ||
568 op.getKind() == ProcedureKind::AlwaysLatch) {
569 auto setInsertionPoint = [&](Value value) {
570 rewriter.setInsertionPoint(op);
572 getValuesToObserve(&op.getBody(), setInsertionPoint, typeConverter,
573 rewriter, observedValues);
576 auto loc = op.getLoc();
577 if (failed(rewriter.convertRegionTypes(&op.getBody(), *typeConverter)))
582 if (op.getKind() == ProcedureKind::Initial ||
583 op.getKind() == ProcedureKind::Final) {
585 if (op.getKind() == ProcedureKind::Initial)
586 newOp = llhd::ProcessOp::create(rewriter, loc, TypeRange{});
588 newOp = llhd::FinalOp::create(rewriter, loc);
589 auto &body = newOp->getRegion(0);
590 rewriter.inlineRegionBefore(op.getBody(), body, body.end());
592 llvm::make_early_inc_range(body.getOps<ReturnOp>())) {
593 rewriter.setInsertionPoint(returnOp);
594 rewriter.replaceOpWithNewOp<llhd::HaltOp>(returnOp, ValueRange{});
596 rewriter.eraseOp(op);
601 auto newOp = llhd::ProcessOp::create(rewriter, loc, TypeRange{});
606 rewriter.createBlock(&newOp.getBody());
607 auto *block = &op.getBody().front();
608 cf::BranchOp::create(rewriter, loc, block);
609 rewriter.inlineRegionBefore(op.getBody(), newOp.getBody(),
610 newOp.getBody().end());
618 if (op.getKind() == ProcedureKind::AlwaysComb ||
619 op.getKind() == ProcedureKind::AlwaysLatch) {
620 Block *waitBlock = rewriter.createBlock(&newOp.getBody());
621 llhd::WaitOp::create(rewriter, loc, ValueRange{}, Value(), observedValues,
622 ValueRange{}, block);
629 for (
auto returnOp :
llvm::make_early_inc_range(newOp.getOps<ReturnOp>())) {
630 rewriter.setInsertionPoint(returnOp);
631 cf::BranchOp::create(rewriter, loc, block);
632 rewriter.eraseOp(returnOp);
635 rewriter.eraseOp(op);
645 using OpConversionPattern::OpConversionPattern;
648 matchAndRewrite(CoroutineOp op, OpAdaptor adaptor,
649 ConversionPatternRewriter &rewriter)
const override {
650 auto funcType = op.getFunctionType();
651 TypeConverter::SignatureConversion sigConversion(funcType.getNumInputs());
652 for (
auto [i, type] :
llvm::enumerate(funcType.getInputs())) {
653 auto converted = typeConverter->convertType(type);
656 sigConversion.addInputs(i, converted);
658 SmallVector<Type> resultTypes;
659 if (failed(typeConverter->convertTypes(funcType.getResults(), resultTypes)))
662 auto newFuncType = FunctionType::get(
663 rewriter.getContext(), sigConversion.getConvertedTypes(), resultTypes);
664 auto newOp = llhd::CoroutineOp::create(rewriter, op.getLoc(),
665 op.getSymName(), newFuncType);
666 newOp.setSymVisibilityAttr(op.getSymVisibilityAttr());
667 rewriter.inlineRegionBefore(op.getBody(), newOp.getBody(),
668 newOp.getBody().end());
669 if (failed(rewriter.convertRegionTypes(&newOp.getBody(), *typeConverter,
675 llvm::make_early_inc_range(newOp.getBody().getOps<ReturnOp>())) {
676 rewriter.setInsertionPoint(returnOp);
677 rewriter.replaceOpWithNewOp<llhd::ReturnOp>(returnOp, ValueRange{});
680 rewriter.eraseOp(op);
686 using OpConversionPattern::OpConversionPattern;
689 matchAndRewrite(CallCoroutineOp op, OpAdaptor adaptor,
690 ConversionPatternRewriter &rewriter)
const override {
691 SmallVector<Type> convResTypes;
692 if (failed(typeConverter->convertTypes(op.getResultTypes(), convResTypes)))
694 rewriter.replaceOpWithNewOp<llhd::CallCoroutineOp>(
695 op, convResTypes, adaptor.getCallee(), adaptor.getOperands());
701 using OpConversionPattern::OpConversionPattern;
704 matchAndRewrite(WaitEventOp op, OpAdaptor adaptor,
705 ConversionPatternRewriter &rewriter)
const override {
739 rewriter.splitBlock(op->getBlock(), ++Block::iterator(op));
745 if (op.getBody().front().empty()) {
748 rewriter.replaceOpWithNewOp<llhd::HaltOp>(op, ValueRange{});
752 auto *waitBlock = rewriter.createBlock(resumeBlock);
753 auto *checkBlock = rewriter.createBlock(resumeBlock);
755 auto loc = op.getLoc();
756 rewriter.setInsertionPoint(op);
757 cf::BranchOp::create(rewriter, loc, waitBlock);
767 SmallVector<Value> valuesBefore;
768 rewriter.setInsertionPointToEnd(waitBlock);
769 auto clonedOp = cast<WaitEventOp>(rewriter.clone(*op));
770 bool allDetectsAreAnyChange =
true;
772 llvm::make_early_inc_range(clonedOp.getOps<DetectEventOp>())) {
773 if (detectOp.getEdge() != Edge::AnyChange || detectOp.getCondition())
774 allDetectsAreAnyChange =
false;
775 valuesBefore.push_back(detectOp.getInput());
776 rewriter.eraseOp(detectOp);
782 SmallVector<Value> observeValues;
783 auto setInsertionPointAfterDef = [&](Value value) {
784 if (
auto *op = value.getDefiningOp())
785 rewriter.setInsertionPointAfter(op);
786 if (
auto arg = dyn_cast<BlockArgument>(value))
787 rewriter.setInsertionPointToStart(value.getParentBlock());
790 getValuesToObserve(&clonedOp.getBody(), setInsertionPointAfterDef,
791 typeConverter, rewriter, observeValues);
796 auto waitOp = llhd::WaitOp::create(rewriter, loc, ValueRange{}, Value(),
797 observeValues, ValueRange{}, checkBlock);
798 rewriter.inlineBlockBefore(&clonedOp.getBody().front(), waitOp);
799 rewriter.eraseOp(clonedOp);
803 SmallVector<DetectEventOp> detectOps(op.getBody().getOps<DetectEventOp>());
804 rewriter.inlineBlockBefore(&op.getBody().front(), checkBlock,
806 rewriter.eraseOp(op);
810 auto computeTrigger = [&](Value before, Value after, Edge edge) -> Value {
811 assert(before.getType() == after.getType() &&
812 "mismatched types after clone op");
813 auto beforeType = cast<IntType>(before.getType());
817 if (beforeType.getWidth() != 1 && edge != Edge::AnyChange) {
818 constexpr int LSB = 0;
820 IntType::get(rewriter.getContext(), 1, beforeType.getDomain());
822 moore::ExtractOp::create(rewriter, loc, beforeType, before, LSB);
823 after = moore::ExtractOp::create(rewriter, loc, beforeType, after, LSB);
826 auto intType = rewriter.getIntegerType(beforeType.getWidth());
827 before = typeConverter->materializeTargetConversion(rewriter, loc,
829 after = typeConverter->materializeTargetConversion(rewriter, loc, intType,
832 if (edge == Edge::AnyChange)
833 return comb::ICmpOp::create(rewriter, loc, ICmpPredicate::ne, before,
836 SmallVector<Value> disjuncts;
839 if (edge == Edge::PosEdge || edge == Edge::BothEdges) {
841 comb::XorOp::create(rewriter, loc, before, trueVal,
true);
843 comb::AndOp::create(rewriter, loc, notOldVal, after,
true);
844 disjuncts.push_back(posedge);
847 if (edge == Edge::NegEdge || edge == Edge::BothEdges) {
849 comb::XorOp::create(rewriter, loc, after, trueVal,
true);
851 comb::AndOp::create(rewriter, loc, before, notCurrVal,
true);
852 disjuncts.push_back(posedge);
855 return rewriter.createOrFold<
comb::OrOp>(loc, disjuncts,
true);
862 SmallVector<Value> triggers;
863 for (
auto [detectOp, before] :
llvm::zip(detectOps, valuesBefore)) {
864 if (!allDetectsAreAnyChange) {
865 if (!isa<IntType>(before.getType()))
866 return detectOp->emitError() <<
"requires int operand";
868 rewriter.setInsertionPoint(detectOp);
870 computeTrigger(before, detectOp.getInput(), detectOp.getEdge());
871 if (detectOp.getCondition()) {
872 auto condition = typeConverter->materializeTargetConversion(
873 rewriter, loc, rewriter.getI1Type(), detectOp.getCondition());
875 comb::AndOp::create(rewriter, loc, trigger, condition,
true);
877 triggers.push_back(trigger);
880 rewriter.eraseOp(detectOp);
883 rewriter.setInsertionPointToEnd(checkBlock);
884 if (triggers.empty()) {
889 cf::BranchOp::create(rewriter, loc, resumeBlock);
895 auto triggered = rewriter.createOrFold<
comb::OrOp>(loc, triggers,
true);
896 cf::CondBranchOp::create(rewriter, loc, triggered, resumeBlock,
905static LogicalResult
convert(WaitDelayOp op, WaitDelayOp::Adaptor adaptor,
906 ConversionPatternRewriter &rewriter) {
908 rewriter.splitBlock(op->getBlock(), ++Block::iterator(op));
909 rewriter.setInsertionPoint(op);
910 rewriter.replaceOpWithNewOp<llhd::WaitOp>(op, ValueRange{},
911 adaptor.getDelay(), ValueRange{},
912 ValueRange{}, resumeBlock);
913 rewriter.setInsertionPointToStart(resumeBlock);
918static LogicalResult
convert(UnreachableOp op, UnreachableOp::Adaptor adaptor,
919 ConversionPatternRewriter &rewriter) {
920 rewriter.replaceOpWithNewOp<llhd::HaltOp>(op, ValueRange{});
929 ConversionPatternRewriter &rewriter) {
931 if (isa<mlir::LLVM::LLVMPointerType>(type))
932 return mlir::LLVM::ZeroOp::create(rewriter, loc, type);
935 if (isa<llhd::TimeType>(type)) {
937 llhd::TimeAttr::get(type.getContext(), 0U, llvm::StringRef(
"ns"), 0, 0);
938 return llhd::ConstantTimeOp::create(rewriter, loc, timeAttr);
942 if (
auto floatType = dyn_cast<FloatType>(type)) {
943 auto floatAttr = rewriter.getFloatAttr(floatType, 0.0);
944 return mlir::arith::ConstantOp::create(rewriter, loc, floatAttr);
948 if (
auto strType = dyn_cast<sim::DynamicStringType>(type))
949 return sim::StringConstantOp::create(rewriter, loc, strType,
"");
952 if (
auto queueType = dyn_cast<sim::QueueType>(type))
953 return sim::QueueEmptyOp::create(rewriter, loc, queueType);
956 int64_t width = hw::getBitWidth(type);
964 return rewriter.createOrFold<
hw::BitcastOp>(loc, type, constZero);
967struct ClassPropertyRefOpConversion
969 ClassPropertyRefOpConversion(TypeConverter &tc, MLIRContext *ctx,
970 ClassTypeCache &cache)
974 matchAndRewrite(circt::moore::ClassPropertyRefOp op, OpAdaptor adaptor,
975 ConversionPatternRewriter &rewriter)
const override {
976 Location loc = op.getLoc();
977 MLIRContext *ctx = rewriter.getContext();
980 Type dstTy = getTypeConverter()->convertType(op.getPropertyRef().getType());
982 Value instRef = adaptor.getInstance();
986 cast<circt::moore::ClassHandleType>(op.getInstance().getType());
987 SymbolRefAttr classSym = classRefTy.getClassSym();
988 ModuleOp mod = op->getParentOfType<ModuleOp>();
989 if (failed(resolveClassStructBody(mod, classSym, *typeConverter, cache)))
990 return rewriter.notifyMatchFailure(op,
991 "Could not resolve class struct for " +
992 classSym.getRootReference().str());
994 auto structInfo = cache.getStructInfo(classSym);
995 assert(structInfo &&
"class struct info must exist");
996 auto structTy = structInfo->classBody;
999 auto propSym = op.getProperty();
1000 auto pathOpt = structInfo->getFieldPath(propSym);
1002 return rewriter.notifyMatchFailure(op,
1003 "no GEP path for property " + propSym);
1005 auto i32Ty = IntegerType::get(ctx, 32);
1006 SmallVector<Value> idxVals;
1007 for (
unsigned idx : *pathOpt)
1008 idxVals.push_back(LLVM::ConstantOp::create(
1009 rewriter, loc, i32Ty, rewriter.getI32IntegerAttr(idx)));
1012 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
1014 LLVM::GEPOp::create(rewriter, loc, ptrTy, structTy, instRef, idxVals);
1017 Value fieldRef = UnrealizedConversionCastOp::create(rewriter, loc, dstTy,
1021 rewriter.replaceOp(op, fieldRef);
1026 ClassTypeCache &cache;
1030 using OpConversionPattern::OpConversionPattern;
1033 matchAndRewrite(ClassUpcastOp op, OpAdaptor adaptor,
1034 ConversionPatternRewriter &rewriter)
const override {
1036 Type dstTy = getTypeConverter()->convertType(op.getResult().getType());
1037 Type srcTy = adaptor.getInstance().getType();
1040 return rewriter.notifyMatchFailure(op,
"failed to convert result type");
1043 if (dstTy == srcTy && isa<LLVM::LLVMPointerType>(srcTy)) {
1044 rewriter.replaceOp(op, adaptor.getInstance());
1047 return rewriter.notifyMatchFailure(
1048 op,
"Upcast applied to non-opaque pointers!");
1054 ClassNewOpConversion(TypeConverter &tc, MLIRContext *ctx,
1055 ClassTypeCache &cache, FunctionCache &funcCache)
1057 funcCache(funcCache) {}
1060 matchAndRewrite(ClassNewOp op, OpAdaptor adaptor,
1061 ConversionPatternRewriter &rewriter)
const override {
1062 Location loc = op.getLoc();
1063 MLIRContext *ctx = rewriter.getContext();
1065 auto handleTy = cast<ClassHandleType>(op.getResult().getType());
1066 auto sym = handleTy.getClassSym();
1068 ModuleOp mod = op->getParentOfType<ModuleOp>();
1070 if (failed(resolveClassStructBody(mod, sym, *typeConverter, cache)))
1071 return op.emitError() <<
"Could not resolve class struct for " << sym;
1073 auto structTy = cache.getStructInfo(sym)->classBody;
1074 auto typeInfo = cache.getStructInfo(sym)->typeInfo;
1079 for (
auto memberTy : structTy.getBody()) {
1080 if (!LLVM::isCompatibleType(memberTy) &&
1081 !memberTy.hasTrait<DataLayoutTypeInterface::Trait>()) {
1082 return op.emitError()
1083 <<
"class struct has member types with no data layout";
1089 uint64_t byteSize = dl.getTypeSize(structTy);
1090 auto i64Ty = IntegerType::get(ctx, 64);
1091 auto cSize = LLVM::ConstantOp::create(rewriter, loc, i64Ty,
1092 rewriter.getI64IntegerAttr(byteSize));
1095 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
1096 auto mallocFn = funcCache.getOrCreate(rewriter,
"malloc", {i64Ty}, {ptrTy});
1098 func::CallOp::create(rewriter, loc, mallocFn, ValueRange{cSize});
1101 LLVM::AddressOfOp::create(rewriter, loc, typeInfo.global);
1102 auto i32Ty = IntegerType::get(ctx, 32);
1103 auto headerIdx = LLVM::ConstantOp::create(
1104 rewriter, loc, i32Ty,
1105 rewriter.getI32IntegerAttr(cache.getStructInfo(sym)->headerFieldIndex));
1106 auto typeInfoIdx = LLVM::ConstantOp::create(
1107 rewriter, loc, i32Ty,
1108 rewriter.getI32IntegerAttr(
1109 cache.getStructInfo(sym)->typeInfoFieldIndex));
1111 LLVM::GEPOp::create(rewriter, loc, ptrTy, structTy, call.getResult(0),
1112 ValueRange{headerIdx, typeInfoIdx});
1113 LLVM::StoreOp::create(rewriter, loc, typeInfoAddr, headerPtr);
1117 rewriter.replaceOp(op, call.getResult(0));
1122 ClassTypeCache &cache;
1123 FunctionCache &funcCache;
1127 ClassDeclOpConversion(TypeConverter &tc, MLIRContext *ctx,
1128 ClassTypeCache &cache)
1132 matchAndRewrite(ClassDeclOp op, OpAdaptor,
1133 ConversionPatternRewriter &rewriter)
const override {
1135 if (failed(resolveClassStructBody(op, *typeConverter, cache)))
1138 rewriter.eraseOp(op);
1143 ClassTypeCache &cache;
1147 using OpConversionPattern::OpConversionPattern;
1150 matchAndRewrite(VariableOp op, OpAdaptor adaptor,
1151 ConversionPatternRewriter &rewriter)
const override {
1152 auto loc = op.getLoc();
1153 auto resultType = typeConverter->convertType(op.getResult().getType());
1155 return rewriter.notifyMatchFailure(op.getLoc(),
"invalid variable type");
1158 Value init = adaptor.getInitial();
1160 auto refType = dyn_cast<llhd::RefType>(resultType);
1162 return rewriter.notifyMatchFailure(
1163 op.getLoc(),
"variable type did not convert to llhd::RefType");
1169 rewriter.replaceOpWithNewOp<llhd::SignalOp>(op, resultType,
1170 op.getNameAttr(), init);
1176 using OpConversionPattern::OpConversionPattern;
1179 matchAndRewrite(NetOp op, OpAdaptor adaptor,
1180 ConversionPatternRewriter &rewriter)
const override {
1181 auto loc = op.getLoc();
1183 auto resultType = typeConverter->convertType(op.getResult().getType());
1185 return rewriter.notifyMatchFailure(loc,
"invalid net type");
1187 auto elementType = cast<llhd::RefType>(resultType).getNestedType();
1193 createInitialValue(op.getKind(), rewriter, loc, width,
elementType);
1194 auto signal = rewriter.replaceOpWithNewOp<llhd::SignalOp>(
1195 op, resultType, op.getNameAttr(), init);
1197 if (
auto assignedValue = adaptor.getAssignment()) {
1198 auto timeAttr = llhd::TimeAttr::get(resultType.getContext(), 0U,
1199 llvm::StringRef(
"ns"), 0, 1);
1200 auto time = llhd::ConstantTimeOp::create(rewriter, loc, timeAttr);
1201 llhd::DriveOp::create(rewriter, loc, signal, assignedValue, time,
1208 static mlir::Value createInitialValue(NetKind kind,
1209 ConversionPatternRewriter &rewriter,
1210 Location loc, int64_t width,
1221 if (kind == NetKind::Supply1 || kind == NetKind::Tri1)
1222 return APInt::getAllOnes(width);
1223 return APInt::getZero(width);
1231static LogicalResult
convert(GlobalVariableOp op,
1232 GlobalVariableOp::Adaptor adaptor,
1233 ConversionPatternRewriter &rewriter,
1234 const TypeConverter &typeConverter) {
1235 auto type = typeConverter.convertType(op.getType());
1236 auto sig = llhd::GlobalSignalOp::create(rewriter, op.getLoc(),
1237 op.getSymNameAttr(), type);
1238 sig.getInitRegion().takeBody(op.getInitRegion());
1239 rewriter.eraseOp(op);
1244static LogicalResult
convert(GetGlobalVariableOp op,
1245 GetGlobalVariableOp::Adaptor adaptor,
1246 ConversionPatternRewriter &rewriter,
1247 const TypeConverter &typeConverter) {
1248 auto type = typeConverter.convertType(op.getType());
1249 rewriter.replaceOpWithNewOp<llhd::GetGlobalSignalOp>(op, type,
1250 op.getGlobalNameAttr());
1259 using OpConversionPattern::OpConversionPattern;
1262 matchAndRewrite(ConstantOp op, OpAdaptor adaptor,
1263 ConversionPatternRewriter &rewriter)
const override {
1265 auto value = op.getValue().toAPInt(
false);
1266 auto type = rewriter.getIntegerType(value.getBitWidth());
1268 op, type, rewriter.getIntegerAttr(type, value));
1274 using OpConversionPattern::OpConversionPattern;
1277 matchAndRewrite(ConstantRealOp op, OpAdaptor adaptor,
1278 ConversionPatternRewriter &rewriter)
const override {
1279 rewriter.replaceOpWithNewOp<arith::ConstantOp>(op, op.getValueAttr());
1285 using OpConversionPattern::OpConversionPattern;
1288 matchAndRewrite(ConstantTimeOp op, OpAdaptor adaptor,
1289 ConversionPatternRewriter &rewriter)
const override {
1290 rewriter.replaceOpWithNewOp<llhd::ConstantTimeOp>(
1291 op, llhd::TimeAttr::get(op->getContext(), op.getValue(),
1292 StringRef(
"fs"), 0, 0));
1298 using OpConversionPattern::OpConversionPattern;
1300 matchAndRewrite(moore::ConstantStringOp op, OpAdaptor adaptor,
1301 ConversionPatternRewriter &rewriter)
const override {
1302 const auto resultType =
1303 typeConverter->convertType(op.getResult().getType());
1304 const auto intType = mlir::cast<IntegerType>(resultType);
1306 const auto str = op.getValue();
1307 const unsigned byteWidth = intType.getWidth();
1308 APInt value(byteWidth, 0);
1311 const size_t maxChars =
1312 std::min(str.size(),
static_cast<size_t>(byteWidth / 8));
1313 for (
size_t i = 0; i < maxChars; i++) {
1314 const size_t pos = str.size() - 1 - i;
1315 const auto asciiChar =
static_cast<uint8_t
>(str[pos]);
1316 value |= APInt(byteWidth, asciiChar) << (8 * i);
1320 op, resultType, rewriter.getIntegerAttr(resultType, value));
1326 using OpConversionPattern::OpConversionPattern;
1328 matchAndRewrite(ConcatOp op, OpAdaptor adaptor,
1329 ConversionPatternRewriter &rewriter)
const override {
1330 rewriter.replaceOpWithNewOp<
comb::ConcatOp>(op, adaptor.getValues());
1336 using OpConversionPattern::OpConversionPattern;
1338 matchAndRewrite(ReplicateOp op, OpAdaptor adaptor,
1339 ConversionPatternRewriter &rewriter)
const override {
1340 Type resultType = typeConverter->convertType(op.getResult().getType());
1342 rewriter.replaceOpWithNewOp<comb::ReplicateOp>(op, resultType,
1343 adaptor.getValue());
1349 using OpConversionPattern::OpConversionPattern;
1352 matchAndRewrite(ExtractOp op, OpAdaptor adaptor,
1353 ConversionPatternRewriter &rewriter)
const override {
1356 Type resultType = typeConverter->convertType(op.getResult().getType());
1357 Type inputType = adaptor.getInput().getType();
1358 int32_t low = adaptor.getLowBit();
1360 if (isa<IntegerType>(inputType)) {
1361 int32_t inputWidth = inputType.getIntOrFloatBitWidth();
1362 int32_t resultWidth = hw::getBitWidth(resultType);
1363 int32_t high = low + resultWidth;
1365 SmallVector<Value> toConcat;
1368 rewriter, op.getLoc(), APInt(std::min(-low, resultWidth), 0)));
1370 if (low < inputWidth && high > 0) {
1371 int32_t lowIdx = std::max(low, 0);
1374 rewriter.getIntegerType(
1375 std::min(resultWidth, std::min(high, inputWidth) - lowIdx)),
1376 adaptor.getInput(), lowIdx);
1377 toConcat.push_back(middle);
1380 int32_t diff = high - inputWidth;
1384 toConcat.push_back(val);
1389 rewriter.replaceOp(op, concat);
1393 if (
auto arrTy = dyn_cast<hw::ArrayType>(inputType)) {
1394 int32_t width = llvm::Log2_64_Ceil(arrTy.getNumElements());
1395 int32_t inputWidth = arrTy.getNumElements();
1397 if (
auto resArrTy = dyn_cast<hw::ArrayType>(resultType);
1398 resArrTy && resArrTy != arrTy.getElementType()) {
1399 int32_t elementWidth = hw::getBitWidth(arrTy.getElementType());
1400 if (elementWidth < 0)
1403 int32_t high = low + resArrTy.getNumElements();
1404 int32_t resWidth = resArrTy.getNumElements();
1406 SmallVector<Value> toConcat;
1409 rewriter, op.getLoc(),
1410 APInt(std::min((-low) * elementWidth, resWidth * elementWidth),
1413 op.getLoc(), hw::ArrayType::get(arrTy.getElementType(), -low),
1415 toConcat.push_back(res);
1418 if (low < inputWidth && high > 0) {
1419 int32_t lowIdx = std::max(0, low);
1421 rewriter, op.getLoc(), rewriter.getIntegerType(width), lowIdx);
1425 arrTy.getElementType(),
1426 std::min(resWidth, std::min(inputWidth, high) - lowIdx)),
1427 adaptor.getInput(), lowIdxVal);
1428 toConcat.push_back(middle);
1431 int32_t diff = high - inputWidth;
1434 rewriter, op.getLoc(), APInt(diff * elementWidth, 0));
1436 rewriter, op.getLoc(),
1437 hw::ArrayType::get(arrTy.getElementType(), diff), constZero);
1438 toConcat.push_back(val);
1443 rewriter.replaceOp(op, concat);
1448 if (low < 0 || low >= inputWidth) {
1449 int32_t bw = hw::getBitWidth(resultType);
1455 rewriter.createOrFold<
hw::BitcastOp>(op.getLoc(), resultType, val);
1456 rewriter.replaceOp(op, bitcast);
1461 rewriter.getIntegerType(width),
1462 adaptor.getLowBit());
1463 rewriter.replaceOpWithNewOp<
hw::ArrayGetOp>(op, adaptor.getInput(), idx);
1472 using OpConversionPattern::OpConversionPattern;
1475 matchAndRewrite(ExtractRefOp op, OpAdaptor adaptor,
1476 ConversionPatternRewriter &rewriter)
const override {
1478 Type resultType = typeConverter->convertType(op.getResult().getType());
1480 cast<llhd::RefType>(adaptor.getInput().getType()).getNestedType();
1482 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1483 int64_t width = hw::getBitWidth(inputType);
1488 rewriter, op.getLoc(),
1489 rewriter.getIntegerType(llvm::Log2_64_Ceil(width)),
1490 adaptor.getLowBit());
1491 rewriter.replaceOpWithNewOp<llhd::SigExtractOp>(
1492 op, resultType, adaptor.getInput(), lowBit);
1496 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1498 rewriter, op.getLoc(),
1499 rewriter.getIntegerType(llvm::Log2_64_Ceil(arrType.getNumElements())),
1500 adaptor.getLowBit());
1504 if (arrType.getElementType() !=
1505 cast<llhd::RefType>(resultType).getNestedType()) {
1506 rewriter.replaceOpWithNewOp<llhd::SigArraySliceOp>(
1507 op, resultType, adaptor.getInput(), lowBit);
1511 rewriter.replaceOpWithNewOp<llhd::SigArrayGetOp>(op, adaptor.getInput(),
1521 using OpConversionPattern::OpConversionPattern;
1524 matchAndRewrite(DynExtractOp op, OpAdaptor adaptor,
1525 ConversionPatternRewriter &rewriter)
const override {
1526 Type resultType = typeConverter->convertType(op.getResult().getType());
1527 Type inputType = adaptor.getInput().getType();
1529 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1530 Value amount = adjustIntegerWidth(rewriter, adaptor.getLowBit(),
1531 intType.getWidth(), op->getLoc());
1532 Value value = comb::ShrUOp::create(rewriter, op->getLoc(),
1533 adaptor.getInput(), amount);
1535 rewriter.replaceOpWithNewOp<
comb::ExtractOp>(op, resultType, value, 0);
1539 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1540 unsigned idxWidth = llvm::Log2_64_Ceil(arrType.getNumElements());
1541 Value idx = adjustIntegerWidth(rewriter, adaptor.getLowBit(), idxWidth,
1544 bool isSingleElementExtract = arrType.getElementType() == resultType;
1546 if (isSingleElementExtract)
1547 rewriter.replaceOpWithNewOp<
hw::ArrayGetOp>(op, adaptor.getInput(),
1551 adaptor.getInput(), idx);
1561 using OpConversionPattern::OpConversionPattern;
1564 matchAndRewrite(DynExtractRefOp op, OpAdaptor adaptor,
1565 ConversionPatternRewriter &rewriter)
const override {
1567 Type resultType = typeConverter->convertType(op.getResult().getType());
1569 cast<llhd::RefType>(adaptor.getInput().getType()).getNestedType();
1571 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1572 int64_t width = hw::getBitWidth(inputType);
1577 adjustIntegerWidth(rewriter, adaptor.getLowBit(),
1578 llvm::Log2_64_Ceil(width), op->getLoc());
1579 rewriter.replaceOpWithNewOp<llhd::SigExtractOp>(
1580 op, resultType, adaptor.getInput(), amount);
1584 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1585 Value idx = adjustIntegerWidth(
1586 rewriter, adaptor.getLowBit(),
1587 llvm::Log2_64_Ceil(arrType.getNumElements()), op->getLoc());
1589 auto resultNestedType = cast<llhd::RefType>(resultType).getNestedType();
1590 bool isSingleElementExtract =
1591 arrType.getElementType() == resultNestedType;
1593 if (isSingleElementExtract)
1594 rewriter.replaceOpWithNewOp<llhd::SigArrayGetOp>(op, adaptor.getInput(),
1597 rewriter.replaceOpWithNewOp<llhd::SigArraySliceOp>(
1598 op, resultType, adaptor.getInput(), idx);
1608 using OpConversionPattern::OpConversionPattern;
1611 matchAndRewrite(ArrayCreateOp op, OpAdaptor adaptor,
1612 ConversionPatternRewriter &rewriter)
const override {
1613 Type resultType = typeConverter->convertType(op.getResult().getType());
1615 adaptor.getElements());
1621 using OpConversionPattern::OpConversionPattern;
1624 matchAndRewrite(StructCreateOp op, OpAdaptor adaptor,
1625 ConversionPatternRewriter &rewriter)
const override {
1626 Type resultType = typeConverter->convertType(op.getResult().getType());
1628 adaptor.getFields());
1634 using OpConversionPattern::OpConversionPattern;
1637 matchAndRewrite(StructExtractOp op, OpAdaptor adaptor,
1638 ConversionPatternRewriter &rewriter)
const override {
1640 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1645struct StructExtractRefOpConversion
1647 using OpConversionPattern::OpConversionPattern;
1650 matchAndRewrite(StructExtractRefOp op, OpAdaptor adaptor,
1651 ConversionPatternRewriter &rewriter)
const override {
1652 rewriter.replaceOpWithNewOp<llhd::SigStructExtractOp>(
1653 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1659 using OpConversionPattern::OpConversionPattern;
1662 matchAndRewrite(UnionCreateOp op, OpAdaptor adaptor,
1663 ConversionPatternRewriter &rewriter)
const override {
1664 Type resultType = typeConverter->convertType(op.getResult().getType());
1665 rewriter.replaceOpWithNewOp<hw::UnionCreateOp>(
1666 op, resultType, adaptor.getFieldNameAttr(), adaptor.getInput());
1672 using OpConversionPattern::OpConversionPattern;
1675 matchAndRewrite(UnionExtractOp op, OpAdaptor adaptor,
1676 ConversionPatternRewriter &rewriter)
const override {
1677 rewriter.replaceOpWithNewOp<hw::UnionExtractOp>(op, adaptor.getInput(),
1678 adaptor.getFieldNameAttr());
1683struct UnionExtractRefOpConversion
1685 using OpConversionPattern::OpConversionPattern;
1688 matchAndRewrite(UnionExtractRefOp op, OpAdaptor adaptor,
1689 ConversionPatternRewriter &rewriter)
const override {
1690 rewriter.replaceOpWithNewOp<llhd::SigStructExtractOp>(
1691 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1697 using OpConversionPattern::OpConversionPattern;
1699 matchAndRewrite(ReduceAndOp op, OpAdaptor adaptor,
1700 ConversionPatternRewriter &rewriter)
const override {
1701 Type resultType = typeConverter->convertType(op.getInput().getType());
1704 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::eq,
1705 adaptor.getInput(), max);
1711 using OpConversionPattern::OpConversionPattern;
1713 matchAndRewrite(ReduceOrOp op, OpAdaptor adaptor,
1714 ConversionPatternRewriter &rewriter)
const override {
1715 Type resultType = typeConverter->convertType(op.getInput().getType());
1718 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1719 adaptor.getInput(), zero);
1725 using OpConversionPattern::OpConversionPattern;
1727 matchAndRewrite(ReduceXorOp op, OpAdaptor adaptor,
1728 ConversionPatternRewriter &rewriter)
const override {
1730 rewriter.replaceOpWithNewOp<
comb::ParityOp>(op, adaptor.getInput());
1736 using OpConversionPattern::OpConversionPattern;
1738 matchAndRewrite(BoolCastOp op, OpAdaptor adaptor,
1739 ConversionPatternRewriter &rewriter)
const override {
1740 Type resultType = typeConverter->convertType(op.getInput().getType());
1741 if (isa_and_nonnull<IntegerType>(resultType)) {
1744 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1745 adaptor.getInput(), zero);
1748 if (isa_and_nonnull<FloatType>(resultType)) {
1749 Value zero = arith::ConstantOp::create(
1750 rewriter, op->getLoc(), rewriter.getFloatAttr(resultType, 0.0));
1751 rewriter.replaceOpWithNewOp<arith::CmpFOp>(op, arith::CmpFPredicate::ONE,
1752 adaptor.getInput(), zero);
1760 using OpConversionPattern::OpConversionPattern;
1762 matchAndRewrite(NotOp op, OpAdaptor adaptor,
1763 ConversionPatternRewriter &rewriter)
const override {
1765 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1768 rewriter.replaceOpWithNewOp<
comb::XorOp>(op, adaptor.getInput(), max);
1774 using OpConversionPattern::OpConversionPattern;
1776 matchAndRewrite(NegOp op, OpAdaptor adaptor,
1777 ConversionPatternRewriter &rewriter)
const override {
1779 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1782 rewriter.replaceOpWithNewOp<
comb::SubOp>(op, zero, adaptor.getInput());
1788 using OpConversionPattern::OpConversionPattern;
1790 matchAndRewrite(NegRealOp op, OpAdaptor adaptor,
1791 ConversionPatternRewriter &rewriter)
const override {
1792 rewriter.replaceOpWithNewOp<arith::NegFOp>(op, adaptor.getInput());
1797template <
typename SourceOp,
typename TargetOp>
1800 using OpAdaptor =
typename SourceOp::Adaptor;
1803 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1804 ConversionPatternRewriter &rewriter)
const override {
1805 rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(),
1806 adaptor.getRhs(),
false);
1811template <
typename SourceOp,
typename TargetOp>
1814 using OpAdaptor =
typename SourceOp::Adaptor;
1817 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1818 ConversionPatternRewriter &rewriter)
const override {
1819 rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(),
1825template <
typename SourceOp, ICmpPredicate pred>
1828 using OpAdaptor =
typename SourceOp::Adaptor;
1831 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1832 ConversionPatternRewriter &rewriter)
const override {
1834 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1836 rewriter.replaceOpWithNewOp<comb::ICmpOp>(
1837 op, resultType, pred, adaptor.getLhs(), adaptor.getRhs());
1842template <
typename SourceOp, arith::CmpFPredicate pred>
1845 using OpAdaptor =
typename SourceOp::Adaptor;
1848 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1849 ConversionPatternRewriter &rewriter)
const override {
1851 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1853 rewriter.replaceOpWithNewOp<arith::CmpFOp>(
1854 op, resultType, pred, adaptor.getLhs(), adaptor.getRhs());
1859template <
typename SourceOp,
bool withoutX>
1862 using OpAdaptor =
typename SourceOp::Adaptor;
1865 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1866 ConversionPatternRewriter &rewriter)
const override {
1872 unsigned bitWidth = op.getLhs().getType().getWidth();
1873 auto ignoredBits = APInt::getZero(bitWidth);
1874 auto detectIgnoredBits = [&](Value value) {
1875 auto constOp = value.getDefiningOp<ConstantOp>();
1878 auto constValue = constOp.getValue();
1880 ignoredBits |= constValue.getZBits();
1882 ignoredBits |= constValue.getUnknownBits();
1884 detectIgnoredBits(op.getLhs());
1885 detectIgnoredBits(op.getRhs());
1889 Value lhs = adaptor.getLhs();
1890 Value rhs = adaptor.getRhs();
1891 if (!ignoredBits.isZero()) {
1892 ignoredBits.flipAllBits();
1894 lhs = rewriter.createOrFold<
comb::AndOp>(op.getLoc(), lhs, maskOp);
1895 rhs = rewriter.createOrFold<
comb::AndOp>(op.getLoc(), rhs, maskOp);
1898 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, ICmpPredicate::ceq, lhs, rhs);
1908 using OpConversionPattern::OpConversionPattern;
1911 matchAndRewrite(ConversionOp op, OpAdaptor adaptor,
1912 ConversionPatternRewriter &rewriter)
const override {
1913 Location loc = op.getLoc();
1914 Type resultType = typeConverter->convertType(op.getResult().getType());
1916 op.emitError(
"conversion result type is not currently supported");
1919 int64_t inputBw = hw::getBitWidth(adaptor.getInput().getType());
1920 int64_t resultBw = hw::getBitWidth(resultType);
1921 if (inputBw == -1 || resultBw == -1) {
1922 if (isSupportedDpiOpenArrayCast(op.getInput().getType(),
1923 op.getResult().getType())) {
1924 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
1925 op, resultType, adaptor.getInput());
1928 if (hasOpenArrayBoundaryType(op.getInput().getType()) ||
1929 hasOpenArrayBoundaryType(op.getResult().getType())) {
1930 op.emitError(
"unsupported DPI open-array conversion from ")
1931 << op.getInput().getType() <<
" to " << op.getResult().getType();
1938 loc, rewriter.getIntegerType(inputBw), adaptor.getInput());
1939 Value amount = adjustIntegerWidth(rewriter, input, resultBw, loc);
1942 rewriter.createOrFold<
hw::BitcastOp>(loc, resultType, amount);
1943 rewriter.replaceOp(op, result);
1948template <
typename SourceOp>
1951 using OpAdaptor =
typename SourceOp::Adaptor;
1952 using ConversionPattern::typeConverter;
1955 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1956 ConversionPatternRewriter &rewriter)
const override {
1957 auto type = typeConverter->convertType(op.getResult().getType());
1958 if (type == adaptor.getInput().getType())
1959 rewriter.replaceOp(op, adaptor.getInput());
1961 rewriter.replaceOpWithNewOp<
hw::BitcastOp>(op, type, adaptor.getInput());
1967template <
typename SourceOp>
1970 using OpAdaptor =
typename SourceOp::Adaptor;
1971 using ConversionPattern::typeConverter;
1974 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1975 ConversionPatternRewriter &rewriter)
const override {
1976 rewriter.replaceOp(op, adaptor.getInput());
1982 using OpConversionPattern::OpConversionPattern;
1985 matchAndRewrite(TruncOp op, OpAdaptor adaptor,
1986 ConversionPatternRewriter &rewriter)
const override {
1987 rewriter.replaceOpWithNewOp<
comb::ExtractOp>(op, adaptor.getInput(), 0,
1988 op.getType().getWidth());
1994 using OpConversionPattern::OpConversionPattern;
1997 matchAndRewrite(ZExtOp op, OpAdaptor adaptor,
1998 ConversionPatternRewriter &rewriter)
const override {
1999 auto targetWidth = op.getType().getWidth();
2000 auto inputWidth = op.getInput().getType().getWidth();
2003 rewriter, op.getLoc(),
2004 rewriter.getIntegerType(targetWidth - inputWidth), 0);
2007 op, ValueRange{zeroExt, adaptor.getInput()});
2013 using OpConversionPattern::OpConversionPattern;
2016 matchAndRewrite(SExtOp op, OpAdaptor adaptor,
2017 ConversionPatternRewriter &rewriter)
const override {
2018 auto type = typeConverter->convertType(op.getType());
2020 comb::createOrFoldSExt(rewriter, op.getLoc(), adaptor.getInput(), type);
2021 rewriter.replaceOp(op, value);
2027 using OpConversionPattern::OpConversionPattern;
2030 matchAndRewrite(SIntToRealOp op, OpAdaptor adaptor,
2031 ConversionPatternRewriter &rewriter)
const override {
2032 rewriter.replaceOpWithNewOp<arith::SIToFPOp>(
2033 op, typeConverter->convertType(op.getType()), adaptor.getInput());
2039 using OpConversionPattern::OpConversionPattern;
2042 matchAndRewrite(UIntToRealOp op, OpAdaptor adaptor,
2043 ConversionPatternRewriter &rewriter)
const override {
2044 rewriter.replaceOpWithNewOp<arith::UIToFPOp>(
2045 op, typeConverter->convertType(op.getType()), adaptor.getInput());
2051 using OpConversionPattern::OpConversionPattern;
2054 matchAndRewrite(IntToStringOp op, OpAdaptor adaptor,
2055 ConversionPatternRewriter &rewriter)
const override {
2056 rewriter.replaceOpWithNewOp<sim::IntToStringOp>(op, adaptor.getInput());
2062 using OpConversionPattern::OpConversionPattern;
2065 matchAndRewrite(RealToIntOp op, OpAdaptor adaptor,
2066 ConversionPatternRewriter &rewriter)
const override {
2067 rewriter.replaceOpWithNewOp<arith::FPToSIOp>(
2068 op, typeConverter->convertType(op.getType()), adaptor.getInput());
2074 using OpConversionPattern::OpConversionPattern;
2077 matchAndRewrite(ConvertRealOp op, OpAdaptor adaptor,
2078 ConversionPatternRewriter &rewriter)
const override {
2079 op.getInput().getType().getWidth() < op.getResult().getType().getWidth()
2080 ? rewriter.replaceOpWithNewOp<arith::ExtFOp>(
2081 op, typeConverter->convertType(op.getType()), adaptor.getInput())
2082 : rewriter.replaceOpWithNewOp<arith::TruncFOp>(
2083 op, typeConverter->
convertType(op.getType()), adaptor.getInput());
2093 using OpConversionPattern::OpConversionPattern;
2096 matchAndRewrite(hw::InstanceOp op, OpAdaptor adaptor,
2097 ConversionPatternRewriter &rewriter)
const override {
2098 SmallVector<Type> convResTypes;
2099 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
2102 rewriter.replaceOpWithNewOp<hw::InstanceOp>(
2103 op, convResTypes, op.getInstanceName(), op.getModuleName(),
2104 adaptor.getOperands(), op.getArgNames(),
2105 op.getResultNames(),
2106 rewriter.getArrayAttr({}),
nullptr);
2113 using OpConversionPattern::OpConversionPattern;
2116 matchAndRewrite(func::ReturnOp op, OpAdaptor adaptor,
2117 ConversionPatternRewriter &rewriter)
const override {
2118 rewriter.replaceOpWithNewOp<func::ReturnOp>(op, adaptor.getOperands());
2124 using OpConversionPattern::OpConversionPattern;
2127 matchAndRewrite(func::CallOp op, OpAdaptor adaptor,
2128 ConversionPatternRewriter &rewriter)
const override {
2129 SmallVector<Type> convResTypes;
2130 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
2132 rewriter.replaceOpWithNewOp<func::CallOp>(
2133 op, adaptor.getCallee(), convResTypes, adaptor.getOperands());
2138struct FuncDPICallOpConversion
2140 using OpConversionPattern::OpConversionPattern;
2143 matchAndRewrite(moore::FuncDPICallOp op, OpAdaptor adaptor,
2144 ConversionPatternRewriter &rewriter)
const override {
2145 SmallVector<Type> convResTypes;
2146 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
2148 rewriter.replaceOpWithNewOp<sim::DPICallOp>(
2149 op, convResTypes, op.getCalleeAttr(), Value(),
2150 Value(), adaptor.getInputs());
2156 using OpConversionPattern::OpConversionPattern;
2159 matchAndRewrite(moore::DPIFuncOp op, OpAdaptor adaptor,
2160 ConversionPatternRewriter &rewriter)
const override {
2162 auto toDPIDir = [](moore::DPIArgDirection dir) -> sim::DPIDirection {
2164 case moore::DPIArgDirection::In:
2165 return sim::DPIDirection::Input;
2166 case moore::DPIArgDirection::Out:
2167 return sim::DPIDirection::Output;
2168 case moore::DPIArgDirection::InOut:
2169 return sim::DPIDirection::InOut;
2170 case moore::DPIArgDirection::Return:
2171 return sim::DPIDirection::Return;
2173 llvm_unreachable(
"unknown DPIArgDirection");
2177 auto dirs = op.getDpiArgDirs();
2178 auto names = op.getDpiArgNames();
2179 SmallVector<Type> argTypes;
2180 op.getDPIArgTypes(argTypes);
2182 SmallVector<sim::DPIArgument> dpiArguments;
2183 for (
auto [dirAttr, nameAttr, mooreType] :
2184 llvm::zip(dirs, names, argTypes)) {
2185 auto dir = toDPIDir(cast<moore::DPIArgDirectionAttr>(dirAttr).getValue());
2186 auto name = cast<StringAttr>(nameAttr);
2187 Type coreType = typeConverter->convertType(mooreType);
2189 return op.emitOpError(
"argument '")
2190 << name <<
"' has unsupported type " << mooreType;
2191 dpiArguments.push_back({name, coreType, dir});
2194 auto coreDPIFuncType =
2195 sim::DPIFunctionType::get(rewriter.getContext(), dpiArguments);
2196 auto simFunc = sim::DPIFuncOp::create(
2197 rewriter, op.getLoc(), op.getSymNameAttr(), coreDPIFuncType,
2198 op.getArgumentLocsAttr(), op.getVerilogNameAttr());
2199 SymbolTable::setSymbolVisibility(simFunc,
2200 SymbolTable::getSymbolVisibility(op));
2201 rewriter.eraseOp(op);
2206struct UnrealizedConversionCastConversion
2208 using OpConversionPattern::OpConversionPattern;
2211 matchAndRewrite(UnrealizedConversionCastOp op, OpAdaptor adaptor,
2212 ConversionPatternRewriter &rewriter)
const override {
2213 SmallVector<Type> convResTypes;
2214 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
2219 if (convResTypes == adaptor.getOperands().getTypes()) {
2220 rewriter.replaceOp(op, adaptor.getOperands());
2224 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
2225 op, convResTypes, adaptor.getOperands());
2231 using OpConversionPattern::OpConversionPattern;
2234 matchAndRewrite(ShlOp op, OpAdaptor adaptor,
2235 ConversionPatternRewriter &rewriter)
const override {
2236 Type resultType = typeConverter->convertType(op.getResult().getType());
2240 adjustIntegerWidth(rewriter, adaptor.getAmount(),
2241 resultType.getIntOrFloatBitWidth(), op->getLoc());
2242 rewriter.replaceOpWithNewOp<
comb::ShlOp>(op, resultType, adaptor.getValue(),
2249 using OpConversionPattern::OpConversionPattern;
2252 matchAndRewrite(ShrOp op, OpAdaptor adaptor,
2253 ConversionPatternRewriter &rewriter)
const override {
2254 Type resultType = typeConverter->convertType(op.getResult().getType());
2258 adjustIntegerWidth(rewriter, adaptor.getAmount(),
2259 resultType.getIntOrFloatBitWidth(), op->getLoc());
2261 op, resultType, adaptor.getValue(), amount,
false);
2267 using OpConversionPattern::OpConversionPattern;
2270 matchAndRewrite(PowUOp op, OpAdaptor adaptor,
2271 ConversionPatternRewriter &rewriter)
const override {
2272 Type resultType = typeConverter->convertType(op.getResult().getType());
2274 Location loc = op->getLoc();
2279 auto lhs = comb::ConcatOp::create(rewriter, loc, zeroVal, adaptor.getLhs());
2280 auto rhs = comb::ConcatOp::create(rewriter, loc, zeroVal, adaptor.getRhs());
2283 auto pow = mlir::math::IPowIOp::create(rewriter, loc, lhs, rhs);
2291 using OpConversionPattern::OpConversionPattern;
2294 matchAndRewrite(PowSOp op, OpAdaptor adaptor,
2295 ConversionPatternRewriter &rewriter)
const override {
2296 Type resultType = typeConverter->convertType(op.getResult().getType());
2300 rewriter.replaceOpWithNewOp<mlir::math::IPowIOp>(
2301 op, resultType, adaptor.getLhs(), adaptor.getRhs());
2307 using OpConversionPattern::OpConversionPattern;
2310 matchAndRewrite(AShrOp op, OpAdaptor adaptor,
2311 ConversionPatternRewriter &rewriter)
const override {
2312 Type resultType = typeConverter->convertType(op.getResult().getType());
2316 adjustIntegerWidth(rewriter, adaptor.getAmount(),
2317 resultType.getIntOrFloatBitWidth(), op->getLoc());
2319 op, resultType, adaptor.getValue(), amount,
false);
2325 using OpConversionPattern::OpConversionPattern;
2328 matchAndRewrite(ReadOp op, OpAdaptor adaptor,
2329 ConversionPatternRewriter &rewriter)
const override {
2330 rewriter.replaceOpWithNewOp<llhd::ProbeOp>(op, adaptor.getInput());
2335struct AssignedVariableOpConversion
2337 using OpConversionPattern::OpConversionPattern;
2340 matchAndRewrite(AssignedVariableOp op, OpAdaptor adaptor,
2341 ConversionPatternRewriter &rewriter)
const override {
2342 rewriter.replaceOpWithNewOp<hw::WireOp>(op, adaptor.getInput(),
2343 adaptor.getNameAttr());
2349static llhd::TimeAttr
2350getBlockingOrContinuousAssignDelay(mlir::MLIRContext *
context) {
2351 return llhd::TimeAttr::get(
context, 0U,
"ns", 0, 1);
2354template <
typename OpTy>
2357 using OpAdaptor =
typename OpTy::Adaptor;
2360 matchAndRewrite(OpTy op, OpAdaptor adaptor,
2361 ConversionPatternRewriter &rewriter)
const override {
2364 if constexpr (std::is_same_v<OpTy, ContinuousAssignOp> ||
2365 std::is_same_v<OpTy, BlockingAssignOp>) {
2366 delay = llhd::ConstantTimeOp::create(
2367 rewriter, op->getLoc(),
2368 getBlockingOrContinuousAssignDelay(op->getContext()));
2369 }
else if constexpr (std::is_same_v<OpTy, NonBlockingAssignOp>) {
2371 delay = llhd::ConstantTimeOp::create(
2372 rewriter, op->getLoc(),
2373 llhd::TimeAttr::get(op->getContext(), 0U,
"ns", 1, 0));
2376 delay = adaptor.getDelay();
2379 rewriter.replaceOpWithNewOp<llhd::DriveOp>(
2380 op, adaptor.getDst(), adaptor.getSrc(), delay, Value{});
2386 using OpConversionPattern::OpConversionPattern;
2389 matchAndRewrite(ConditionalOp op, OpAdaptor adaptor,
2390 ConversionPatternRewriter &rewriter)
const override {
2395 auto type = typeConverter->convertType(op.getType());
2397 auto hasNoWriteEffect = [](Region ®ion) {
2398 auto result = region.walk([](Operation *operation) {
2399 if (
auto memOp = dyn_cast<MemoryEffectOpInterface>(operation))
2400 if (!memOp.hasEffect<MemoryEffects::Write>() &&
2401 !memOp.hasEffect<MemoryEffects::Free>())
2402 return WalkResult::advance();
2404 if (operation->hasTrait<OpTrait::HasRecursiveMemoryEffects>())
2405 return WalkResult::advance();
2407 return WalkResult::interrupt();
2409 return !result.wasInterrupted();
2412 if (hasNoWriteEffect(op.getTrueRegion()) &&
2413 hasNoWriteEffect(op.getFalseRegion())) {
2414 Operation *trueTerm = op.getTrueRegion().front().getTerminator();
2415 Operation *falseTerm = op.getFalseRegion().front().getTerminator();
2417 rewriter.inlineBlockBefore(&op.getTrueRegion().front(), op);
2418 rewriter.inlineBlockBefore(&op.getFalseRegion().front(), op);
2420 Value convTrueVal = typeConverter->materializeTargetConversion(
2421 rewriter, op.getLoc(), type, trueTerm->getOperand(0));
2422 Value convFalseVal = typeConverter->materializeTargetConversion(
2423 rewriter, op.getLoc(), type, falseTerm->getOperand(0));
2425 rewriter.eraseOp(trueTerm);
2426 rewriter.eraseOp(falseTerm);
2428 rewriter.replaceOpWithNewOp<
comb::MuxOp>(op, adaptor.getCondition(),
2429 convTrueVal, convFalseVal);
2434 scf::IfOp::create(rewriter, op.getLoc(), type, adaptor.getCondition());
2435 rewriter.inlineRegionBefore(op.getTrueRegion(), ifOp.getThenRegion(),
2436 ifOp.getThenRegion().end());
2437 rewriter.inlineRegionBefore(op.getFalseRegion(), ifOp.getElseRegion(),
2438 ifOp.getElseRegion().end());
2439 rewriter.replaceOp(op, ifOp);
2445 using OpConversionPattern::OpConversionPattern;
2448 matchAndRewrite(YieldOp op, OpAdaptor adaptor,
2449 ConversionPatternRewriter &rewriter)
const override {
2450 if (isa<llhd::GlobalSignalOp>(op->getParentOp()))
2451 rewriter.replaceOpWithNewOp<llhd::YieldOp>(op, adaptor.getResult());
2453 rewriter.replaceOpWithNewOp<scf::YieldOp>(op, adaptor.getResult());
2458template <
typename SourceOp>
2461 using OpAdaptor =
typename SourceOp::Adaptor;
2464 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
2465 ConversionPatternRewriter &rewriter)
const override {
2466 rewriter.modifyOpInPlace(op,
2467 [&]() { op->setOperands(adaptor.getOperands()); });
2472template <
typename MooreOpTy,
typename VerifOpTy>
2475 using OpAdaptor =
typename MooreOpTy::Adaptor;
2478 matchAndRewrite(MooreOpTy op, OpAdaptor adaptor,
2479 ConversionPatternRewriter &rewriter)
const override {
2481 op.getLabel().has_value()
2482 ? StringAttr::get(op->getContext(), op.getLabel().value())
2483 : StringAttr::
get(op->getContext());
2484 rewriter.replaceOpWithNewOp<VerifOpTy>(op, adaptor.getCond(), mlir::Value(),
2495 using OpConversionPattern::OpConversionPattern;
2498 matchAndRewrite(FormatLiteralOp op, OpAdaptor adaptor,
2499 ConversionPatternRewriter &rewriter)
const override {
2500 rewriter.replaceOpWithNewOp<sim::FormatLiteralOp>(op, adaptor.getLiteral());
2506 using OpConversionPattern::OpConversionPattern;
2509 matchAndRewrite(FormatStringOp op, OpAdaptor adaptor,
2510 ConversionPatternRewriter &rewriter)
const override {
2512 op.getPadding().value_or(IntPadding::Space) == IntPadding::Space ? 32
2514 IntegerAttr padCharAttr = rewriter.getI8IntegerAttr(padChar);
2515 auto widthAttr = adaptor.getWidthAttr();
2517 bool isLeftAligned =
2518 op.getAlignment().value_or(IntAlign::Right) == IntAlign::Left;
2519 BoolAttr isLeftAlignedAttr = rewriter.getBoolAttr(isLeftAligned);
2521 rewriter.replaceOpWithNewOp<sim::FormatStringOp>(
2522 op, adaptor.getString(), isLeftAlignedAttr, padCharAttr, widthAttr);
2528 using OpConversionPattern::OpConversionPattern;
2531 matchAndRewrite(FormatConcatOp op, OpAdaptor adaptor,
2532 ConversionPatternRewriter &rewriter)
const override {
2533 rewriter.replaceOpWithNewOp<sim::FormatStringConcatOp>(op,
2534 adaptor.getInputs());
2539struct FormatHierPathOpConversion
2541 using OpConversionPattern::OpConversionPattern;
2544 matchAndRewrite(FormatHierPathOp op, OpAdaptor adaptor,
2545 ConversionPatternRewriter &rewriter)
const override {
2546 rewriter.replaceOpWithNewOp<sim::FormatHierPathOp>(op,
2547 adaptor.getUseEscapes());
2553 using OpConversionPattern::OpConversionPattern;
2556 matchAndRewrite(FormatIntOp op, OpAdaptor adaptor,
2557 ConversionPatternRewriter &rewriter)
const override {
2559 char padChar = adaptor.getPadding() == IntPadding::Space ? 32 : 48;
2560 IntegerAttr padCharAttr = rewriter.getI8IntegerAttr(padChar);
2561 auto widthAttr = adaptor.getSpecifierWidthAttr();
2563 bool isLeftAligned = adaptor.getAlignment() == IntAlign::Left;
2564 BoolAttr isLeftAlignedAttr = rewriter.getBoolAttr(isLeftAligned);
2566 switch (op.getFormat()) {
2567 case IntFormat::Decimal:
2568 rewriter.replaceOpWithNewOp<sim::FormatDecOp>(
2569 op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr,
2570 adaptor.getIsSignedAttr());
2572 case IntFormat::Binary:
2573 rewriter.replaceOpWithNewOp<sim::FormatBinOp>(
2574 op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr);
2576 case IntFormat::Octal:
2577 rewriter.replaceOpWithNewOp<sim::FormatOctOp>(
2578 op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr);
2580 case IntFormat::HexLower:
2581 rewriter.replaceOpWithNewOp<sim::FormatHexOp>(
2582 op, adaptor.getValue(), rewriter.getBoolAttr(
false),
2583 isLeftAlignedAttr, padCharAttr, widthAttr);
2585 case IntFormat::HexUpper:
2586 rewriter.replaceOpWithNewOp<sim::FormatHexOp>(
2587 op, adaptor.getValue(), rewriter.getBoolAttr(
true), isLeftAlignedAttr,
2588 padCharAttr, widthAttr);
2591 return rewriter.notifyMatchFailure(op,
"unsupported int format");
2596 using OpConversionPattern::OpConversionPattern;
2599 matchAndRewrite(FormatRealOp op, OpAdaptor adaptor,
2600 ConversionPatternRewriter &rewriter)
const override {
2601 auto fracDigitsAttr = adaptor.getFracDigitsAttr();
2603 auto fieldWidthAttr = adaptor.getFieldWidthAttr();
2604 bool isLeftAligned = adaptor.getAlignment() == IntAlign::Left;
2605 mlir::BoolAttr isLeftAlignedAttr = rewriter.getBoolAttr(isLeftAligned);
2607 switch (op.getFormat()) {
2608 case RealFormat::General:
2609 rewriter.replaceOpWithNewOp<sim::FormatGeneralOp>(
2610 op, adaptor.getValue(), isLeftAlignedAttr, fieldWidthAttr,
2613 case RealFormat::Float:
2614 rewriter.replaceOpWithNewOp<sim::FormatFloatOp>(
2615 op, adaptor.getValue(), isLeftAlignedAttr, fieldWidthAttr,
2618 case RealFormat::Exponential:
2619 rewriter.replaceOpWithNewOp<sim::FormatScientificOp>(
2620 op, adaptor.getValue(), isLeftAlignedAttr, fieldWidthAttr,
2628 using OpConversionPattern::OpConversionPattern;
2631 matchAndRewrite(StringLenOp op, OpAdaptor adaptor,
2632 ConversionPatternRewriter &rewriter)
const override {
2633 rewriter.replaceOpWithNewOp<sim::StringLengthOp>(op, adaptor.getStr());
2639 using OpConversionPattern::OpConversionPattern;
2642 matchAndRewrite(StringConcatOp op, OpAdaptor adaptor,
2643 ConversionPatternRewriter &rewriter)
const override {
2644 rewriter.replaceOpWithNewOp<sim::StringConcatOp>(op, adaptor.getInputs());
2650 using OpConversionPattern::OpConversionPattern;
2653 matchAndRewrite(StringGetOp op, OpAdaptor adaptor,
2654 ConversionPatternRewriter &rewriter)
const override {
2655 rewriter.replaceOpWithNewOp<sim::StringGetOp>(op, adaptor.getStr(),
2656 adaptor.getIndex());
2662 using OpConversionPattern::OpConversionPattern;
2665 matchAndRewrite(QueueSizeBIOp op, OpAdaptor adaptor,
2666 ConversionPatternRewriter &rewriter)
const override {
2667 rewriter.replaceOpWithNewOp<sim::QueueSizeOp>(op, adaptor.getQueue());
2672struct DynQueueExtractOpConversion
2674 using OpConversionPattern::OpConversionPattern;
2677 matchAndRewrite(DynQueueExtractOp op, OpAdaptor adaptor,
2678 ConversionPatternRewriter &rewriter)
const override {
2679 bool isSingleElementExtract =
2680 op.getInput().getType().getElementType() == op.getResult().getType();
2682 if (isSingleElementExtract) {
2683 rewriter.replaceOpWithNewOp<sim::QueueGetOp>(op, adaptor.getInput(),
2684 adaptor.getLowerIdx());
2686 rewriter.replaceOpWithNewOp<sim::QueueSliceOp>(
2687 op, adaptor.getInput(), adaptor.getLowerIdx(), adaptor.getUpperIdx());
2703probeRefAndDriveWithResult(OpBuilder &builder, Location loc, Value ref,
2704 const std::function<Value(Value)> &func) {
2706 Value v = llhd::ProbeOp::create(builder, loc, ref);
2709 Value delay = llhd::ConstantTimeOp::create(
2710 builder, loc, getBlockingOrContinuousAssignDelay(builder.getContext()));
2712 llhd::DriveOp::create(builder, loc, ref, func(v), delay, Value{});
2716 using OpConversionPattern::OpConversionPattern;
2719 matchAndRewrite(QueuePushBackOp op, OpAdaptor adaptor,
2720 ConversionPatternRewriter &rewriter)
const override {
2721 probeRefAndDriveWithResult(
2722 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2723 return sim::QueuePushBackOp::create(rewriter, op->getLoc(), queue,
2724 adaptor.getElement());
2727 rewriter.eraseOp(op);
2732struct QueuePushFrontOpConversion
2734 using OpConversionPattern::OpConversionPattern;
2737 matchAndRewrite(QueuePushFrontOp op, OpAdaptor adaptor,
2738 ConversionPatternRewriter &rewriter)
const override {
2740 probeRefAndDriveWithResult(
2741 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2742 return sim::QueuePushFrontOp::create(rewriter, op->getLoc(), queue,
2743 adaptor.getElement());
2746 rewriter.eraseOp(op);
2752 using OpConversionPattern::OpConversionPattern;
2755 matchAndRewrite(QueuePopBackOp op, OpAdaptor adaptor,
2756 ConversionPatternRewriter &rewriter)
const override {
2758 probeRefAndDriveWithResult(
2759 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2761 sim::QueuePopBackOp::create(rewriter, op->getLoc(), queue);
2762 popped = popBack.getPopped();
2763 return popBack.getOutQueue();
2765 rewriter.replaceOp(op, popped);
2772 using OpConversionPattern::OpConversionPattern;
2775 matchAndRewrite(QueuePopFrontOp op, OpAdaptor adaptor,
2776 ConversionPatternRewriter &rewriter)
const override {
2778 probeRefAndDriveWithResult(
2779 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2781 sim::QueuePopFrontOp::create(rewriter, op->getLoc(), queue);
2782 popped = popFront.getPopped();
2783 return popFront.getOutQueue();
2785 rewriter.replaceOp(op, popped);
2792 using OpConversionPattern::OpConversionPattern;
2795 matchAndRewrite(QueueClearOp op, OpAdaptor adaptor,
2796 ConversionPatternRewriter &rewriter)
const override {
2797 auto refType = cast<llhd::RefType>(adaptor.getQueue().getType());
2798 auto queueType = refType.getNestedType();
2800 sim::QueueEmptyOp::create(rewriter, op->getLoc(), queueType);
2803 Value delay = llhd::ConstantTimeOp::create(
2804 rewriter, op.getLoc(),
2805 getBlockingOrContinuousAssignDelay(rewriter.getContext()));
2807 llhd::DriveOp::create(rewriter, op.getLoc(), adaptor.getQueue(), emptyQueue,
2810 rewriter.eraseOp(op);
2816 using OpConversionPattern::OpConversionPattern;
2819 matchAndRewrite(QueueInsertOp op, OpAdaptor adaptor,
2820 ConversionPatternRewriter &rewriter)
const override {
2821 probeRefAndDriveWithResult(
2822 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2824 sim::QueueInsertOp::create(rewriter, op->getLoc(), queue,
2825 adaptor.getIndex(), adaptor.getItem());
2827 return insert.getOutQueue();
2829 rewriter.eraseOp(op);
2836 using OpConversionPattern::OpConversionPattern;
2839 matchAndRewrite(QueueDeleteOp op, OpAdaptor adaptor,
2840 ConversionPatternRewriter &rewriter)
const override {
2841 probeRefAndDriveWithResult(
2842 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2843 auto delOp = sim::QueueDeleteOp::create(rewriter, op->getLoc(), queue,
2844 adaptor.getIndex());
2846 return delOp.getOutQueue();
2848 rewriter.eraseOp(op);
2855 using OpConversionPattern::OpConversionPattern;
2858 matchAndRewrite(QueueResizeOp op, OpAdaptor adaptor,
2859 ConversionPatternRewriter &rewriter)
const override {
2861 rewriter.replaceOpWithNewOp<sim::QueueResizeOp>(
2862 op, getTypeConverter()->convertType(op.getResult().getType()),
2863 adaptor.getInput());
2869 using OpConversionPattern::OpConversionPattern;
2871 matchAndRewrite(QueueSetOp op, OpAdaptor adaptor,
2872 ConversionPatternRewriter &rewriter)
const override {
2873 probeRefAndDriveWithResult(
2874 rewriter, op->getLoc(), adaptor.getQueue(), [&](Value queue) {
2876 sim::QueueSetOp::create(rewriter, op.getLoc(), queue,
2877 adaptor.getIndex(), adaptor.getItem());
2878 return setOp.getOutQueue();
2880 rewriter.eraseOp(op);
2886 using OpConversionPattern::OpConversionPattern;
2889 matchAndRewrite(QueueCmpOp op, OpAdaptor adaptor,
2890 ConversionPatternRewriter &rewriter)
const override {
2898 auto unpackedPred = adaptor.getPredicateAttr().getValue();
2899 sim::QueueCmpPredicate queuePred;
2900 switch (unpackedPred) {
2901 case circt::moore::UArrayCmpPredicate::eq:
2902 queuePred = sim::QueueCmpPredicate::eq;
2904 case circt::moore::UArrayCmpPredicate::ne:
2905 queuePred = sim::QueueCmpPredicate::ne;
2909 auto cmpPred = sim::QueueCmpPredicateAttr::get(getContext(), queuePred);
2911 rewriter.replaceOpWithNewOp<sim::QueueCmpOp>(op, cmpPred, adaptor.getLhs(),
2917struct QueueFromUnpackedArrayOpConversion
2919 using OpConversionPattern::OpConversionPattern;
2922 matchAndRewrite(QueueFromUnpackedArrayOp op, OpAdaptor adaptor,
2923 ConversionPatternRewriter &rewriter)
const override {
2924 rewriter.replaceOpWithNewOp<sim::QueueFromArrayOp>(
2925 op, getTypeConverter()->convertType(op.getResult().getType()),
2926 adaptor.getInput());
2932 using OpConversionPattern::OpConversionPattern;
2935 matchAndRewrite(QueueConcatOp op, OpAdaptor adaptor,
2936 ConversionPatternRewriter &rewriter)
const override {
2937 rewriter.replaceOpWithNewOp<sim::QueueConcatOp>(
2938 op, getTypeConverter()->convertType(op.getResult().getType()),
2939 adaptor.getInputs());
2945 using OpConversionPattern::OpConversionPattern;
2948 matchAndRewrite(DisplayBIOp op, OpAdaptor adaptor,
2949 ConversionPatternRewriter &rewriter)
const override {
2950 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(
2951 op, adaptor.getMessage());
2957 using OpConversionPattern::OpConversionPattern;
2959 matchAndRewrite(FOpenBIOp op, OpAdaptor adaptor,
2960 ConversionPatternRewriter &rewriter)
const override {
2961 sim::SVFOpenModeAttr simMode;
2962 if (
auto modeAttr = op.getModeAttr()) {
2963 auto mapMode = [](moore::FOpenMode m) -> sim::SVFOpenMode {
2965 case moore::FOpenMode::Read:
2966 return sim::SVFOpenMode::Read;
2967 case moore::FOpenMode::Write:
2968 return sim::SVFOpenMode::Write;
2969 case moore::FOpenMode::Append:
2970 return sim::SVFOpenMode::Append;
2971 case moore::FOpenMode::ReadUpdate:
2972 return sim::SVFOpenMode::ReadUpdate;
2973 case moore::FOpenMode::WriteUpdate:
2974 return sim::SVFOpenMode::WriteUpdate;
2975 case moore::FOpenMode::AppendUpdate:
2976 return sim::SVFOpenMode::AppendUpdate;
2978 llvm_unreachable(
"unknown FOpenMode");
2980 simMode = sim::SVFOpenModeAttr::get(op.getContext(),
2981 mapMode(modeAttr.getValue()));
2983 rewriter.replaceOpWithNewOp<sim::SVFOpenOp>(op, adaptor.getFilename(),
2990 using OpConversionPattern::OpConversionPattern;
2993 matchAndRewrite(FCloseBIOp op, OpAdaptor adaptor,
2994 ConversionPatternRewriter &rewriter)
const override {
2995 rewriter.replaceOpWithNewOp<sim::SVFCloseOp>(op, adaptor.getFd());
3007static LogicalResult
convert(StopBIOp op, StopBIOp::Adaptor adaptor,
3008 ConversionPatternRewriter &rewriter) {
3009 rewriter.replaceOpWithNewOp<sim::PauseOp>(op,
false);
3014static LogicalResult
convert(FinishBIOp op, FinishBIOp::Adaptor adaptor,
3015 ConversionPatternRewriter &rewriter) {
3016 rewriter.replaceOpWithNewOp<sim::TerminateOp>(op, op.getExitCode() == 0,
3022static LogicalResult
convert(SeverityBIOp op, SeverityBIOp::Adaptor adaptor,
3023 ConversionPatternRewriter &rewriter) {
3025 std::string severityString;
3027 switch (op.getSeverity()) {
3028 case (Severity::Fatal):
3029 severityString =
"Fatal: ";
3031 case (Severity::Error):
3032 severityString =
"Error: ";
3034 case (Severity::Warning):
3035 severityString =
"Warning: ";
3037 case (Severity::Info):
3038 severityString =
"Info: ";
3043 sim::FormatLiteralOp::create(rewriter, op.getLoc(), severityString);
3044 auto message = sim::FormatStringConcatOp::create(
3045 rewriter, op.getLoc(), ValueRange{prefix, adaptor.getMessage()});
3046 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(op, message);
3060 UrandomRangeBIOp::Adaptor adaptor,
3061 ConversionPatternRewriter &rewriter,
3062 FunctionCache &funcCache) {
3063 auto loc = op.getLoc();
3064 auto i32Ty = rewriter.getI32Type();
3065 auto ptrTy = LLVM::LLVMPointerType::get(rewriter.getContext());
3066 auto fn = funcCache.getOrCreate(rewriter,
"__circt_urandom_range",
3067 {i32Ty, i32Ty, ptrTy}, {i32Ty});
3070 if (
auto seedRef = adaptor.getSeed()) {
3073 seedPtr = LLVM::AllocaOp::create(rewriter, loc, ptrTy, i32Ty, one);
3074 auto seedVal = llhd::ProbeOp::create(rewriter, loc, seedRef);
3075 LLVM::StoreOp::create(rewriter, loc, seedVal, seedPtr);
3077 seedPtr = LLVM::ZeroOp::create(rewriter, loc, ptrTy);
3080 auto call = func::CallOp::create(
3082 ValueRange{adaptor.getMinval(), adaptor.getMaxval(), seedPtr});
3085 if (adaptor.getSeed()) {
3086 auto newSeed = LLVM::LoadOp::create(rewriter, loc, i32Ty, seedPtr);
3087 auto epsilon = llhd::ConstantTimeOp::create(
3089 llhd::TimeAttr::get(rewriter.getContext(), 0,
"ns", 0, 1));
3090 llhd::DriveOp::create(rewriter, loc, adaptor.getSeed(), newSeed, epsilon,
3094 rewriter.replaceOp(op, call.getResult(0));
3100 FinishMessageBIOp::Adaptor adaptor,
3101 ConversionPatternRewriter &rewriter) {
3103 rewriter.eraseOp(op);
3112static LogicalResult
convert(TimeBIOp op, TimeBIOp::Adaptor adaptor,
3113 ConversionPatternRewriter &rewriter) {
3114 rewriter.replaceOpWithNewOp<llhd::CurrentTimeOp>(op);
3119static LogicalResult
convert(LogicToTimeOp op, LogicToTimeOp::Adaptor adaptor,
3120 ConversionPatternRewriter &rewriter) {
3121 rewriter.replaceOpWithNewOp<llhd::IntToTimeOp>(op, adaptor.getInput());
3126static LogicalResult
convert(TimeToLogicOp op, TimeToLogicOp::Adaptor adaptor,
3127 ConversionPatternRewriter &rewriter) {
3128 rewriter.replaceOpWithNewOp<llhd::TimeToIntOp>(op, adaptor.getInput());
3137 const TypeConverter &converter) {
3138 target.addIllegalDialect<MooreDialect>();
3139 target.addLegalDialect<comb::CombDialect>();
3140 target.addLegalDialect<hw::HWDialect>();
3141 target.addLegalDialect<seq::SeqDialect>();
3142 target.addLegalDialect<llhd::LLHDDialect>();
3143 target.addLegalDialect<ltl::LTLDialect>();
3144 target.addLegalDialect<mlir::BuiltinDialect>();
3145 target.addLegalDialect<mlir::math::MathDialect>();
3146 target.addLegalDialect<sim::SimDialect>();
3147 target.addLegalDialect<mlir::LLVM::LLVMDialect>();
3148 target.addLegalDialect<verif::VerifDialect>();
3149 target.addLegalDialect<arith::ArithDialect>();
3151 target.addLegalOp<debug::ScopeOp>();
3153 target.addDynamicallyLegalOp<scf::YieldOp, func::CallOp, func::ReturnOp,
3154 UnrealizedConversionCastOp, hw::OutputOp,
3155 hw::InstanceOp, debug::ArrayOp, debug::StructOp,
3156 debug::VariableOp, arith::SelectOp>(
3157 [&](Operation *op) {
return converter.isLegal(op); });
3159 target.addDynamicallyLegalOp<scf::IfOp, scf::ForOp, scf::ExecuteRegionOp,
3160 scf::WhileOp, scf::ForallOp>([&](Operation *op) {
3161 return converter.isLegal(op) && !op->getParentOfType<llhd::ProcessOp>();
3164 target.addDynamicallyLegalOp<func::FuncOp>([&](func::FuncOp op) {
3165 return converter.isSignatureLegal(op.getFunctionType());
3169 return converter.isSignatureLegal(op.getModuleType().getFuncType()) &&
3170 converter.isLegal(&op.getBody());
3175 typeConverter.addConversion([&](IntType type) {
3176 return IntegerType::get(type.getContext(), type.getWidth());
3179 typeConverter.addConversion([&](RealType type) -> mlir::Type {
3180 MLIRContext *ctx = type.getContext();
3181 switch (type.getWidth()) {
3182 case moore::RealWidth::f32:
3183 return mlir::Float32Type::get(ctx);
3184 case moore::RealWidth::f64:
3185 return mlir::Float64Type::get(ctx);
3189 typeConverter.addConversion(
3190 [&](TimeType type) {
return llhd::TimeType::get(type.getContext()); });
3192 typeConverter.addConversion([&](FormatStringType type) {
3193 return sim::FormatStringType::get(type.getContext());
3196 typeConverter.addConversion([&](StringType type) {
3197 return sim::DynamicStringType::get(type.getContext());
3200 typeConverter.addConversion([&](QueueType type) {
3201 return sim::QueueType::get(type.getContext(),
3202 typeConverter.convertType(type.getElementType()),
3206 typeConverter.addConversion([&](ArrayType type) -> std::optional<Type> {
3207 if (
auto elementType = typeConverter.convertType(type.getElementType()))
3208 return hw::ArrayType::get(
elementType, type.getSize());
3215 typeConverter.addConversion(
3216 [&](UnpackedArrayType type) -> std::optional<Type> {
3217 if (
auto elementType = typeConverter.convertType(type.getElementType()))
3218 return hw::ArrayType::get(
elementType, type.getSize());
3222 typeConverter.addConversion([&](OpenArrayType type) -> std::optional<Type> {
3223 return LLVM::LLVMPointerType::get(type.getContext());
3226 typeConverter.addConversion(
3227 [&](OpenUnpackedArrayType type) -> std::optional<Type> {
3228 return LLVM::LLVMPointerType::get(type.getContext());
3231 typeConverter.addConversion([&](StructType type) -> std::optional<Type> {
3232 SmallVector<hw::StructType::FieldInfo> fields;
3233 for (
auto field : type.getMembers()) {
3234 hw::StructType::FieldInfo info;
3235 info.type = typeConverter.convertType(field.type);
3238 info.name = field.name;
3239 fields.push_back(info);
3241 return hw::StructType::get(type.getContext(), fields);
3249 typeConverter.addConversion(
3250 [&](UnpackedStructType type) -> std::optional<Type> {
3251 SmallVector<hw::StructType::FieldInfo> fields;
3252 for (
auto field : type.getMembers()) {
3253 hw::StructType::FieldInfo info;
3254 info.type = typeConverter.convertType(field.type);
3257 info.name = field.name;
3258 fields.push_back(info);
3260 return hw::StructType::get(type.getContext(), fields);
3264 typeConverter.addConversion([&](UnionType type) -> std::optional<Type> {
3265 SmallVector<hw::UnionType::FieldInfo> fields;
3266 for (
auto field : type.getMembers()) {
3267 hw::UnionType::FieldInfo info;
3268 info.type = typeConverter.convertType(field.type);
3271 info.name = field.name;
3273 fields.push_back(info);
3275 auto result = hw::UnionType::get(type.getContext(), fields);
3280 typeConverter.addConversion(
3281 [&](UnpackedUnionType type) -> std::optional<Type> {
3282 SmallVector<hw::UnionType::FieldInfo> fields;
3283 for (
auto field : type.getMembers()) {
3284 hw::UnionType::FieldInfo info;
3285 info.type = typeConverter.convertType(field.type);
3288 info.name = field.name;
3290 fields.push_back(info);
3292 return hw::UnionType::get(type.getContext(), fields);
3296 typeConverter.addConversion([&](ChandleType type) -> std::optional<Type> {
3297 return LLVM::LLVMPointerType::get(type.getContext());
3301 typeConverter.addConversion(
3302 [](LLVM::LLVMPointerType t) -> std::optional<Type> {
return t; });
3305 typeConverter.addConversion([&](ClassHandleType type) -> std::optional<Type> {
3306 return LLVM::LLVMPointerType::get(type.getContext());
3309 typeConverter.addConversion([&](RefType type) -> std::optional<Type> {
3310 if (isa<OpenArrayType, OpenUnpackedArrayType>(type.getNestedType()))
3311 return LLVM::LLVMPointerType::get(type.getContext());
3312 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
3313 return llhd::RefType::get(innerType);
3318 typeConverter.addConversion([](IntegerType type) {
return type; });
3319 typeConverter.addConversion([](FloatType type) {
return type; });
3320 typeConverter.addConversion([](sim::DynamicStringType type) {
return type; });
3321 typeConverter.addConversion([](llhd::TimeType type) {
return type; });
3322 typeConverter.addConversion([](debug::ArrayType type) {
return type; });
3323 typeConverter.addConversion([](debug::ScopeType type) {
return type; });
3324 typeConverter.addConversion([](debug::StructType type) {
return type; });
3326 typeConverter.addConversion([&](llhd::RefType type) -> std::optional<Type> {
3327 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
3328 return llhd::RefType::get(innerType);
3332 typeConverter.addConversion([&](hw::ArrayType type) -> std::optional<Type> {
3333 if (
auto elementType = typeConverter.convertType(type.getElementType()))
3334 return hw::ArrayType::get(
elementType, type.getNumElements());
3338 typeConverter.addConversion([&](hw::StructType type) -> std::optional<Type> {
3339 SmallVector<hw::StructType::FieldInfo> fields;
3340 for (
auto field : type.getElements()) {
3341 hw::StructType::FieldInfo info;
3342 info.type = typeConverter.convertType(field.type);
3345 info.name = field.name;
3346 fields.push_back(info);
3348 return hw::StructType::get(type.getContext(), fields);
3351 typeConverter.addConversion([&](hw::UnionType type) -> std::optional<Type> {
3352 SmallVector<hw::UnionType::FieldInfo> fields;
3353 for (
auto field : type.getElements()) {
3354 hw::UnionType::FieldInfo info;
3355 info.type = typeConverter.convertType(field.type);
3358 info.name = field.name;
3359 info.offset = field.offset;
3360 fields.push_back(info);
3362 return hw::UnionType::get(type.getContext(), fields);
3365 typeConverter.addTargetMaterialization(
3366 [&](mlir::OpBuilder &builder, mlir::Type resultType,
3367 mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
3368 if (inputs.size() != 1 || !inputs[0])
3370 return UnrealizedConversionCastOp::create(builder, loc, resultType,
3375 typeConverter.addSourceMaterialization(
3376 [&](mlir::OpBuilder &builder, mlir::Type resultType,
3377 mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
3378 if (inputs.size() != 1)
3380 return UnrealizedConversionCastOp::create(builder, loc, resultType,
3387 TypeConverter &typeConverter,
3388 ClassTypeCache &classCache,
3389 FunctionCache &funcCache) {
3394 classCache, funcCache);
3395 patterns.add<ClassPropertyRefOpConversion>(typeConverter,
3396 patterns.getContext(), classCache);
3400 ClassUpcastOpConversion,
3402 VariableOpConversion,
3406 ConversionOpConversion,
3407 BitcastConversion<PackedToSBVOp>,
3408 BitcastConversion<SBVToPackedOp>,
3409 NoOpConversion<LogicToIntOp>,
3410 NoOpConversion<IntToLogicOp>,
3411 NoOpConversion<ToBuiltinIntOp>,
3412 NoOpConversion<FromBuiltinIntOp>,
3416 SIntToRealOpConversion,
3417 UIntToRealOpConversion,
3418 IntToStringOpConversion,
3419 RealToIntOpConversion,
3420 ConvertRealOpConversion,
3426 ReplicateOpConversion,
3428 ExtractOpConversion,
3429 DynExtractOpConversion,
3430 DynExtractRefOpConversion,
3432 StructExtractOpConversion,
3433 StructExtractRefOpConversion,
3434 ExtractRefOpConversion,
3435 StructCreateOpConversion,
3436 UnionCreateOpConversion,
3437 UnionExtractOpConversion,
3438 UnionExtractRefOpConversion,
3439 ConditionalOpConversion,
3440 ArrayCreateOpConversion,
3443 ConstantStringOpConv,
3446 ReduceAndOpConversion,
3447 ReduceOrOpConversion,
3448 ReduceXorOpConversion,
3449 BoolCastOpConversion,
3454 BinaryOpConversion<AddOp, comb::AddOp>,
3455 BinaryOpConversion<SubOp, comb::SubOp>,
3456 BinaryOpConversion<MulOp, comb::MulOp>,
3457 BinaryOpConversion<DivUOp, comb::DivUOp>,
3458 BinaryOpConversion<DivSOp, comb::DivSOp>,
3459 BinaryOpConversion<ModUOp, comb::ModUOp>,
3460 BinaryOpConversion<ModSOp, comb::ModSOp>,
3461 BinaryOpConversion<AndOp, comb::AndOp>,
3462 BinaryOpConversion<OrOp, comb::OrOp>,
3463 BinaryOpConversion<XorOp, comb::XorOp>,
3466 NegRealOpConversion,
3469 BinaryRealOpConversion<AddRealOp, arith::AddFOp>,
3470 BinaryRealOpConversion<SubRealOp, arith::SubFOp>,
3471 BinaryRealOpConversion<DivRealOp, arith::DivFOp>,
3472 BinaryRealOpConversion<MulRealOp, arith::MulFOp>,
3473 BinaryRealOpConversion<PowRealOp, math::PowFOp>,
3476 PowUOpConversion, PowSOpConversion,
3479 ICmpOpConversion<UltOp, ICmpPredicate::ult>,
3480 ICmpOpConversion<SltOp, ICmpPredicate::slt>,
3481 ICmpOpConversion<UleOp, ICmpPredicate::ule>,
3482 ICmpOpConversion<SleOp, ICmpPredicate::sle>,
3483 ICmpOpConversion<UgtOp, ICmpPredicate::ugt>,
3484 ICmpOpConversion<SgtOp, ICmpPredicate::sgt>,
3485 ICmpOpConversion<UgeOp, ICmpPredicate::uge>,
3486 ICmpOpConversion<SgeOp, ICmpPredicate::sge>,
3487 ICmpOpConversion<EqOp, ICmpPredicate::eq>,
3488 ICmpOpConversion<NeOp, ICmpPredicate::ne>,
3489 ICmpOpConversion<CaseEqOp, ICmpPredicate::ceq>,
3490 ICmpOpConversion<CaseNeOp, ICmpPredicate::cne>,
3491 ICmpOpConversion<WildcardEqOp, ICmpPredicate::weq>,
3492 ICmpOpConversion<WildcardNeOp, ICmpPredicate::wne>,
3493 FCmpOpConversion<NeRealOp, arith::CmpFPredicate::ONE>,
3494 FCmpOpConversion<FltOp, arith::CmpFPredicate::OLT>,
3495 FCmpOpConversion<FleOp, arith::CmpFPredicate::OLE>,
3496 FCmpOpConversion<FgtOp, arith::CmpFPredicate::OGT>,
3497 FCmpOpConversion<FgeOp, arith::CmpFPredicate::OGE>,
3498 FCmpOpConversion<EqRealOp, arith::CmpFPredicate::OEQ>,
3499 CaseXZEqOpConversion<CaseZEqOp, true>,
3500 CaseXZEqOpConversion<CaseXZEqOp, false>,
3503 SVModuleOpConversion,
3504 InstanceOpConversion,
3505 ProcedureOpConversion,
3506 CoroutineOpConversion,
3507 CallCoroutineOpConversion,
3508 WaitEventOpConversion,
3516 AssignOpConversion<ContinuousAssignOp>,
3517 AssignOpConversion<DelayedContinuousAssignOp>,
3518 AssignOpConversion<BlockingAssignOp>,
3519 AssignOpConversion<NonBlockingAssignOp>,
3520 AssignOpConversion<DelayedNonBlockingAssignOp>,
3521 AssignedVariableOpConversion,
3524 HWInstanceOpConversion,
3527 DPIFuncOpConversion,
3528 FuncDPICallOpConversion,
3529 UnrealizedConversionCastConversion,
3530 InPlaceOpConversion<debug::ArrayOp>,
3531 InPlaceOpConversion<debug::StructOp>,
3532 InPlaceOpConversion<debug::VariableOp>,
3535 AssertLikeOpConversion<AssertOp, verif::AssertOp>,
3536 AssertLikeOpConversion<AssumeOp, verif::AssumeOp>,
3537 AssertLikeOpConversion<CoverOp, verif::CoverOp>,
3540 FormatLiteralOpConversion,
3541 FormatStringOpConversion,
3542 FormatConcatOpConversion,
3543 FormatHierPathOpConversion,
3544 FormatIntOpConversion,
3545 FormatRealOpConversion,
3546 DisplayBIOpConversion,
3549 FOpenBIOpConversion,
3550 FCloseBIOpConversion,
3553 StringLenOpConversion,
3554 StringConcatOpConversion,
3555 StringGetOpConversion,
3558 QueueSizeBIOpConversion,
3559 QueuePushBackOpConversion,
3560 QueuePushFrontOpConversion,
3561 QueuePopBackOpConversion,
3562 QueuePopFrontOpConversion,
3563 QueueDeleteOpConversion,
3564 QueueInsertOpConversion,
3565 QueueClearOpConversion,
3566 DynQueueExtractOpConversion,
3567 QueueResizeOpConversion,
3568 QueueSetOpConversion,
3569 QueueCmpOpConversion,
3570 QueueFromUnpackedArrayOpConversion,
3571 QueueConcatOpConversion
3572 >(typeConverter,
patterns.getContext());
3595 mlir::populateAnyFunctionOpInterfaceTypeConversionPattern(
patterns,
3597 hw::populateHWModuleLikeTypeConversionPattern(
3598 hw::HWModuleOp::getOperationName(),
patterns, typeConverter);
3599 populateSCFToControlFlowConversionPatterns(
patterns);
3608struct MooreToCorePass
3609 :
public circt::impl::ConvertMooreToCoreBase<MooreToCorePass> {
3610 void runOnOperation()
override;
3616 return std::make_unique<MooreToCorePass>();
3620void MooreToCorePass::runOnOperation() {
3621 MLIRContext &
context = getContext();
3622 ModuleOp
module = getOperation();
3623 ClassTypeCache classCache;
3624 auto &symbolTable = getAnalysis<SymbolTable>();
3625 FunctionCache funcCache(symbolTable);
3627 IRRewriter rewriter(module);
3628 (void)mlir::eraseUnreachableBlocks(rewriter, module->getRegions());
3630 TypeConverter typeConverter;
3633 ConversionTarget target(
context);
3638 mlir::cf::populateCFStructuralTypeConversionsAndLegality(typeConverter,
3641 if (failed(applyFullConversion(module, target, std::move(
patterns))))
3642 signalPassFailure();
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static FIRRTLBaseType convertType(FIRRTLBaseType type)
Returns null type if no conversion is needed.
static Value createZeroValue(ImplicitLocOpBuilder &builder, FIRRTLBaseType type, SmallDenseMap< FIRRTLBaseType, Value > &cache)
Construct a zero value of the given type using the given builder.
static LogicalResult convert(StopBIOp op, StopBIOp::Adaptor adaptor, ConversionPatternRewriter &rewriter)
static void populateOpConversion(ConversionPatternSet &patterns, TypeConverter &typeConverter, ClassTypeCache &classCache, FunctionCache &funcCache)
static void populateLegality(ConversionTarget &target, const TypeConverter &converter)
static void populateTypeConversion(TypeConverter &typeConverter)
Extension of RewritePatternSet that allows adding matchAndRewrite functions with op adaptors and Conv...
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void populateArithToCombPatterns(mlir::RewritePatternSet &patterns, TypeConverter &typeConverter)
std::unique_ptr< OperationPass< ModuleOp > > createConvertMooreToCorePass()
Create an Moore to Comb/HW/LLHD conversion pass.
This holds a decoded list of input/inout and output ports for a module or instance.
This holds the name, type, direction of a module's ports.