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 Type type = value.getType();
526 if (
auto refType = dyn_cast<llhd::RefType>(type)) {
527 if (!hw::isHWValueType(refType.getNestedType()))
529 return llhd::ProbeOp::create(rewriter, loc, value);
531 if (!hw::isHWValueType(type))
536 region->getParentOp()->walk<WalkOrder::PreOrder, ForwardDominanceIterator<>>(
537 [&](Operation *operation) {
538 for (
auto value : operation->getOperands()) {
539 if (isa<BlockArgument>(value))
540 value = rewriter.getRemappedValue(value);
542 if (region->isAncestor(value.getParentRegion()))
544 if (
auto *defOp = value.getDefiningOp();
545 defOp && defOp->hasTrait<OpTrait::ConstantLike>())
547 if (!alreadyObserved.insert(value).second)
550 OpBuilder::InsertionGuard g(rewriter);
551 if (
auto remapped = rewriter.getRemappedValue(value)) {
552 setInsertionPoint(remapped);
553 if (
auto observed = probeIfSignal(remapped))
554 observeValues.push_back(observed);
556 setInsertionPoint(value);
557 auto type = typeConverter->convertType(value.getType());
558 auto converted = typeConverter->materializeTargetConversion(
559 rewriter, loc, type, value);
560 if (
auto observed = probeIfSignal(converted))
561 observeValues.push_back(observed);
568 using OpConversionPattern::OpConversionPattern;
571 matchAndRewrite(ProcedureOp op, OpAdaptor adaptor,
572 ConversionPatternRewriter &rewriter)
const override {
574 SmallVector<Value> observedValues;
575 if (op.getKind() == ProcedureKind::AlwaysComb ||
576 op.getKind() == ProcedureKind::AlwaysLatch) {
577 auto setInsertionPoint = [&](Value value) {
578 rewriter.setInsertionPoint(op);
580 getValuesToObserve(&op.getBody(), setInsertionPoint, typeConverter,
581 rewriter, observedValues);
584 auto loc = op.getLoc();
585 if (failed(rewriter.convertRegionTypes(&op.getBody(), *typeConverter)))
590 if (op.getKind() == ProcedureKind::Initial ||
591 op.getKind() == ProcedureKind::Final) {
593 if (op.getKind() == ProcedureKind::Initial)
594 newOp = llhd::ProcessOp::create(rewriter, loc, TypeRange{});
596 newOp = llhd::FinalOp::create(rewriter, loc);
597 auto &body = newOp->getRegion(0);
598 rewriter.inlineRegionBefore(op.getBody(), body, body.end());
600 llvm::make_early_inc_range(body.getOps<ReturnOp>())) {
601 rewriter.setInsertionPoint(returnOp);
602 rewriter.replaceOpWithNewOp<llhd::HaltOp>(returnOp, ValueRange{});
604 rewriter.eraseOp(op);
609 auto newOp = llhd::ProcessOp::create(rewriter, loc, TypeRange{});
614 rewriter.createBlock(&newOp.getBody());
615 auto *block = &op.getBody().front();
616 cf::BranchOp::create(rewriter, loc, block);
617 rewriter.inlineRegionBefore(op.getBody(), newOp.getBody(),
618 newOp.getBody().end());
626 if (op.getKind() == ProcedureKind::AlwaysComb ||
627 op.getKind() == ProcedureKind::AlwaysLatch) {
628 Block *waitBlock = rewriter.createBlock(&newOp.getBody());
629 llhd::WaitOp::create(rewriter, loc, ValueRange{}, Value(), observedValues,
630 ValueRange{}, block);
637 for (
auto returnOp :
llvm::make_early_inc_range(newOp.getOps<ReturnOp>())) {
638 rewriter.setInsertionPoint(returnOp);
639 cf::BranchOp::create(rewriter, loc, block);
640 rewriter.eraseOp(returnOp);
643 rewriter.eraseOp(op);
653 using OpConversionPattern::OpConversionPattern;
656 matchAndRewrite(CoroutineOp op, OpAdaptor adaptor,
657 ConversionPatternRewriter &rewriter)
const override {
658 auto funcType = op.getFunctionType();
659 TypeConverter::SignatureConversion sigConversion(funcType.getNumInputs());
660 for (
auto [i, type] :
llvm::enumerate(funcType.getInputs())) {
661 auto converted = typeConverter->convertType(type);
664 sigConversion.addInputs(i, converted);
666 SmallVector<Type> resultTypes;
667 if (failed(typeConverter->convertTypes(funcType.getResults(), resultTypes)))
670 auto newFuncType = FunctionType::get(
671 rewriter.getContext(), sigConversion.getConvertedTypes(), resultTypes);
672 auto newOp = llhd::CoroutineOp::create(rewriter, op.getLoc(),
673 op.getSymName(), newFuncType);
674 newOp.setSymVisibilityAttr(op.getSymVisibilityAttr());
675 if (
auto dpiExport = op->getAttr(
"circt.dpi.export"))
676 newOp->setAttr(
"circt.dpi.export", dpiExport);
677 rewriter.inlineRegionBefore(op.getBody(), newOp.getBody(),
678 newOp.getBody().end());
679 if (failed(rewriter.convertRegionTypes(&newOp.getBody(), *typeConverter,
685 llvm::make_early_inc_range(newOp.getBody().getOps<ReturnOp>())) {
686 rewriter.setInsertionPoint(returnOp);
687 rewriter.replaceOpWithNewOp<llhd::ReturnOp>(returnOp, ValueRange{});
690 rewriter.eraseOp(op);
696 using OpConversionPattern::OpConversionPattern;
699 matchAndRewrite(CallCoroutineOp op, OpAdaptor adaptor,
700 ConversionPatternRewriter &rewriter)
const override {
701 SmallVector<Type> convResTypes;
702 if (failed(typeConverter->convertTypes(op.getResultTypes(), convResTypes)))
704 rewriter.replaceOpWithNewOp<llhd::CallCoroutineOp>(
705 op, convResTypes, adaptor.getCallee(), adaptor.getOperands());
711 using OpConversionPattern::OpConversionPattern;
714 matchAndRewrite(WaitEventOp op, OpAdaptor adaptor,
715 ConversionPatternRewriter &rewriter)
const override {
749 rewriter.splitBlock(op->getBlock(), ++Block::iterator(op));
755 if (op.getBody().front().empty()) {
758 rewriter.replaceOpWithNewOp<llhd::HaltOp>(op, ValueRange{});
762 auto *waitBlock = rewriter.createBlock(resumeBlock);
763 auto *checkBlock = rewriter.createBlock(resumeBlock);
765 auto loc = op.getLoc();
766 rewriter.setInsertionPoint(op);
767 cf::BranchOp::create(rewriter, loc, waitBlock);
777 SmallVector<Value> valuesBefore;
778 rewriter.setInsertionPointToEnd(waitBlock);
779 auto clonedOp = cast<WaitEventOp>(rewriter.clone(*op));
780 bool allDetectsAreAnyChange =
true;
782 llvm::make_early_inc_range(clonedOp.getOps<DetectEventOp>())) {
783 if (detectOp.getEdge() != Edge::AnyChange || detectOp.getCondition())
784 allDetectsAreAnyChange =
false;
785 valuesBefore.push_back(detectOp.getInput());
786 rewriter.eraseOp(detectOp);
792 SmallVector<Value> observeValues;
793 auto setInsertionPointAfterDef = [&](Value value) {
794 if (
auto *op = value.getDefiningOp())
795 rewriter.setInsertionPointAfter(op);
796 if (
auto arg = dyn_cast<BlockArgument>(value))
797 rewriter.setInsertionPointToStart(value.getParentBlock());
800 getValuesToObserve(&clonedOp.getBody(), setInsertionPointAfterDef,
801 typeConverter, rewriter, observeValues);
806 auto waitOp = llhd::WaitOp::create(rewriter, loc, ValueRange{}, Value(),
807 observeValues, ValueRange{}, checkBlock);
808 rewriter.inlineBlockBefore(&clonedOp.getBody().front(), waitOp);
809 rewriter.eraseOp(clonedOp);
813 SmallVector<DetectEventOp> detectOps(op.getBody().getOps<DetectEventOp>());
814 rewriter.inlineBlockBefore(&op.getBody().front(), checkBlock,
816 rewriter.eraseOp(op);
820 auto computeTrigger = [&](Value before, Value after, Edge edge) -> Value {
821 assert(before.getType() == after.getType() &&
822 "mismatched types after clone op");
823 auto beforeType = cast<IntType>(before.getType());
827 if (beforeType.getWidth() != 1 && edge != Edge::AnyChange) {
828 constexpr int LSB = 0;
830 IntType::get(rewriter.getContext(), 1, beforeType.getDomain());
832 moore::ExtractOp::create(rewriter, loc, beforeType, before, LSB);
833 after = moore::ExtractOp::create(rewriter, loc, beforeType, after, LSB);
836 auto intType = rewriter.getIntegerType(beforeType.getWidth());
837 before = typeConverter->materializeTargetConversion(rewriter, loc,
839 after = typeConverter->materializeTargetConversion(rewriter, loc, intType,
842 if (edge == Edge::AnyChange)
843 return comb::ICmpOp::create(rewriter, loc, ICmpPredicate::ne, before,
846 SmallVector<Value> disjuncts;
849 if (edge == Edge::PosEdge || edge == Edge::BothEdges) {
851 comb::XorOp::create(rewriter, loc, before, trueVal,
true);
853 comb::AndOp::create(rewriter, loc, notOldVal, after,
true);
854 disjuncts.push_back(posedge);
857 if (edge == Edge::NegEdge || edge == Edge::BothEdges) {
859 comb::XorOp::create(rewriter, loc, after, trueVal,
true);
861 comb::AndOp::create(rewriter, loc, before, notCurrVal,
true);
862 disjuncts.push_back(posedge);
865 return rewriter.createOrFold<
comb::OrOp>(loc, disjuncts,
true);
872 SmallVector<Value> triggers;
873 for (
auto [detectOp, before] :
llvm::zip(detectOps, valuesBefore)) {
874 if (!allDetectsAreAnyChange) {
875 if (!isa<IntType>(before.getType()))
876 return detectOp->emitError() <<
"requires int operand";
878 rewriter.setInsertionPoint(detectOp);
880 computeTrigger(before, detectOp.getInput(), detectOp.getEdge());
881 if (detectOp.getCondition()) {
882 auto condition = typeConverter->materializeTargetConversion(
883 rewriter, loc, rewriter.getI1Type(), detectOp.getCondition());
885 comb::AndOp::create(rewriter, loc, trigger, condition,
true);
887 triggers.push_back(trigger);
890 rewriter.eraseOp(detectOp);
893 rewriter.setInsertionPointToEnd(checkBlock);
894 if (triggers.empty()) {
899 cf::BranchOp::create(rewriter, loc, resumeBlock);
905 auto triggered = rewriter.createOrFold<
comb::OrOp>(loc, triggers,
true);
906 cf::CondBranchOp::create(rewriter, loc, triggered, resumeBlock,
915static LogicalResult
convert(WaitDelayOp op, WaitDelayOp::Adaptor adaptor,
916 ConversionPatternRewriter &rewriter) {
918 rewriter.splitBlock(op->getBlock(), ++Block::iterator(op));
919 rewriter.setInsertionPoint(op);
920 rewriter.replaceOpWithNewOp<llhd::WaitOp>(op, ValueRange{},
921 adaptor.getDelay(), ValueRange{},
922 ValueRange{}, resumeBlock);
923 rewriter.setInsertionPointToStart(resumeBlock);
928static LogicalResult
convert(UnreachableOp op, UnreachableOp::Adaptor adaptor,
929 ConversionPatternRewriter &rewriter) {
930 rewriter.replaceOpWithNewOp<llhd::HaltOp>(op, ValueRange{});
939 ConversionPatternRewriter &rewriter) {
941 if (isa<mlir::LLVM::LLVMPointerType>(type))
942 return mlir::LLVM::ZeroOp::create(rewriter, loc, type);
945 if (isa<llhd::TimeType>(type)) {
947 llhd::TimeAttr::get(type.getContext(), 0U, llvm::StringRef(
"ns"), 0, 0);
948 return llhd::ConstantTimeOp::create(rewriter, loc, timeAttr);
952 if (
auto floatType = dyn_cast<FloatType>(type)) {
953 auto floatAttr = rewriter.getFloatAttr(floatType, 0.0);
954 return mlir::arith::ConstantOp::create(rewriter, loc, floatAttr);
958 if (
auto strType = dyn_cast<sim::DynamicStringType>(type))
959 return sim::StringConstantOp::create(rewriter, loc, strType,
"");
962 if (
auto queueType = dyn_cast<sim::QueueType>(type))
963 return sim::QueueEmptyOp::create(rewriter, loc, queueType);
966 int64_t width = hw::getBitWidth(type);
974 return rewriter.createOrFold<
hw::BitcastOp>(loc, type, constZero);
977struct ClassPropertyRefOpConversion
979 ClassPropertyRefOpConversion(TypeConverter &tc, MLIRContext *ctx,
980 ClassTypeCache &cache)
984 matchAndRewrite(circt::moore::ClassPropertyRefOp op, OpAdaptor adaptor,
985 ConversionPatternRewriter &rewriter)
const override {
986 Location loc = op.getLoc();
987 MLIRContext *ctx = rewriter.getContext();
990 Type dstTy = getTypeConverter()->convertType(op.getPropertyRef().getType());
992 Value instRef = adaptor.getInstance();
996 cast<circt::moore::ClassHandleType>(op.getInstance().getType());
997 SymbolRefAttr classSym = classRefTy.getClassSym();
998 ModuleOp mod = op->getParentOfType<ModuleOp>();
999 if (failed(resolveClassStructBody(mod, classSym, *typeConverter, cache)))
1000 return rewriter.notifyMatchFailure(op,
1001 "Could not resolve class struct for " +
1002 classSym.getRootReference().str());
1004 auto structInfo = cache.getStructInfo(classSym);
1005 assert(structInfo &&
"class struct info must exist");
1006 auto structTy = structInfo->classBody;
1009 auto propSym = op.getProperty();
1010 auto pathOpt = structInfo->getFieldPath(propSym);
1012 return rewriter.notifyMatchFailure(op,
1013 "no GEP path for property " + propSym);
1015 auto i32Ty = IntegerType::get(ctx, 32);
1016 SmallVector<Value> idxVals;
1017 for (
unsigned idx : *pathOpt)
1018 idxVals.push_back(LLVM::ConstantOp::create(
1019 rewriter, loc, i32Ty, rewriter.getI32IntegerAttr(idx)));
1022 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
1024 LLVM::GEPOp::create(rewriter, loc, ptrTy, structTy, instRef, idxVals);
1027 Value fieldRef = UnrealizedConversionCastOp::create(rewriter, loc, dstTy,
1031 rewriter.replaceOp(op, fieldRef);
1036 ClassTypeCache &cache;
1040 using OpConversionPattern::OpConversionPattern;
1043 matchAndRewrite(ClassUpcastOp op, OpAdaptor adaptor,
1044 ConversionPatternRewriter &rewriter)
const override {
1046 Type dstTy = getTypeConverter()->convertType(op.getResult().getType());
1047 Type srcTy = adaptor.getInstance().getType();
1050 return rewriter.notifyMatchFailure(op,
"failed to convert result type");
1053 if (dstTy == srcTy && isa<LLVM::LLVMPointerType>(srcTy)) {
1054 rewriter.replaceOp(op, adaptor.getInstance());
1057 return rewriter.notifyMatchFailure(
1058 op,
"Upcast applied to non-opaque pointers!");
1064 ClassNewOpConversion(TypeConverter &tc, MLIRContext *ctx,
1065 ClassTypeCache &cache, FunctionCache &funcCache)
1067 funcCache(funcCache) {}
1070 matchAndRewrite(ClassNewOp op, OpAdaptor adaptor,
1071 ConversionPatternRewriter &rewriter)
const override {
1072 Location loc = op.getLoc();
1073 MLIRContext *ctx = rewriter.getContext();
1075 auto handleTy = cast<ClassHandleType>(op.getResult().getType());
1076 auto sym = handleTy.getClassSym();
1078 ModuleOp mod = op->getParentOfType<ModuleOp>();
1080 if (failed(resolveClassStructBody(mod, sym, *typeConverter, cache)))
1081 return op.emitError() <<
"Could not resolve class struct for " << sym;
1083 auto structTy = cache.getStructInfo(sym)->classBody;
1084 auto typeInfo = cache.getStructInfo(sym)->typeInfo;
1089 for (
auto memberTy : structTy.getBody()) {
1090 if (!LLVM::isCompatibleType(memberTy) &&
1091 !memberTy.hasTrait<DataLayoutTypeInterface::Trait>()) {
1092 return op.emitError()
1093 <<
"class struct has member types with no data layout";
1099 uint64_t byteSize = dl.getTypeSize(structTy);
1100 auto i64Ty = IntegerType::get(ctx, 64);
1101 auto cSize = LLVM::ConstantOp::create(rewriter, loc, i64Ty,
1102 rewriter.getI64IntegerAttr(byteSize));
1105 auto ptrTy = LLVM::LLVMPointerType::get(ctx);
1106 auto mallocFn = funcCache.getOrCreate(rewriter,
"malloc", {i64Ty}, {ptrTy});
1108 func::CallOp::create(rewriter, loc, mallocFn, ValueRange{cSize});
1111 LLVM::AddressOfOp::create(rewriter, loc, typeInfo.global);
1112 auto i32Ty = IntegerType::get(ctx, 32);
1113 auto headerIdx = LLVM::ConstantOp::create(
1114 rewriter, loc, i32Ty,
1115 rewriter.getI32IntegerAttr(cache.getStructInfo(sym)->headerFieldIndex));
1116 auto typeInfoIdx = LLVM::ConstantOp::create(
1117 rewriter, loc, i32Ty,
1118 rewriter.getI32IntegerAttr(
1119 cache.getStructInfo(sym)->typeInfoFieldIndex));
1121 LLVM::GEPOp::create(rewriter, loc, ptrTy, structTy, call.getResult(0),
1122 ValueRange{headerIdx, typeInfoIdx});
1123 LLVM::StoreOp::create(rewriter, loc, typeInfoAddr, headerPtr);
1127 rewriter.replaceOp(op, call.getResult(0));
1132 ClassTypeCache &cache;
1133 FunctionCache &funcCache;
1137 ClassDeclOpConversion(TypeConverter &tc, MLIRContext *ctx,
1138 ClassTypeCache &cache)
1142 matchAndRewrite(ClassDeclOp op, OpAdaptor,
1143 ConversionPatternRewriter &rewriter)
const override {
1145 if (failed(resolveClassStructBody(op, *typeConverter, cache)))
1148 rewriter.eraseOp(op);
1153 ClassTypeCache &cache;
1157 using OpConversionPattern::OpConversionPattern;
1160 matchAndRewrite(VariableOp op, OpAdaptor adaptor,
1161 ConversionPatternRewriter &rewriter)
const override {
1162 auto loc = op.getLoc();
1163 auto resultType = typeConverter->convertType(op.getResult().getType());
1165 return rewriter.notifyMatchFailure(op.getLoc(),
"invalid variable type");
1168 Value init = adaptor.getInitial();
1170 auto refType = dyn_cast<llhd::RefType>(resultType);
1172 return rewriter.notifyMatchFailure(
1173 op.getLoc(),
"variable type did not convert to llhd::RefType");
1179 rewriter.replaceOpWithNewOp<llhd::SignalOp>(op, resultType,
1180 op.getNameAttr(), init);
1186 using OpConversionPattern::OpConversionPattern;
1189 matchAndRewrite(NetOp op, OpAdaptor adaptor,
1190 ConversionPatternRewriter &rewriter)
const override {
1191 auto loc = op.getLoc();
1193 auto resultType = typeConverter->convertType(op.getResult().getType());
1195 return rewriter.notifyMatchFailure(loc,
"invalid net type");
1197 auto elementType = cast<llhd::RefType>(resultType).getNestedType();
1203 createInitialValue(op.getKind(), rewriter, loc, width,
elementType);
1204 auto signal = rewriter.replaceOpWithNewOp<llhd::SignalOp>(
1205 op, resultType, op.getNameAttr(), init);
1207 if (
auto assignedValue = adaptor.getAssignment()) {
1208 auto timeAttr = llhd::TimeAttr::get(resultType.getContext(), 0U,
1209 llvm::StringRef(
"ns"), 0, 1);
1210 auto time = llhd::ConstantTimeOp::create(rewriter, loc, timeAttr);
1211 llhd::DriveOp::create(rewriter, loc, signal, assignedValue, time,
1218 static mlir::Value createInitialValue(NetKind kind,
1219 ConversionPatternRewriter &rewriter,
1220 Location loc, int64_t width,
1231 if (kind == NetKind::Supply1 || kind == NetKind::Tri1)
1232 return APInt::getAllOnes(width);
1233 return APInt::getZero(width);
1241static LogicalResult
convert(GlobalVariableOp op,
1242 GlobalVariableOp::Adaptor adaptor,
1243 ConversionPatternRewriter &rewriter,
1244 const TypeConverter &typeConverter) {
1245 auto type = typeConverter.convertType(op.getType());
1246 auto sig = llhd::GlobalSignalOp::create(rewriter, op.getLoc(),
1247 op.getSymNameAttr(), type);
1248 sig.getInitRegion().takeBody(op.getInitRegion());
1249 rewriter.eraseOp(op);
1254static LogicalResult
convert(GetGlobalVariableOp op,
1255 GetGlobalVariableOp::Adaptor adaptor,
1256 ConversionPatternRewriter &rewriter,
1257 const TypeConverter &typeConverter) {
1258 auto type = typeConverter.convertType(op.getType());
1259 rewriter.replaceOpWithNewOp<llhd::GetGlobalSignalOp>(op, type,
1260 op.getGlobalNameAttr());
1269 using OpConversionPattern::OpConversionPattern;
1272 matchAndRewrite(ConstantOp op, OpAdaptor adaptor,
1273 ConversionPatternRewriter &rewriter)
const override {
1275 auto value = op.getValue().toAPInt(
false);
1276 auto type = rewriter.getIntegerType(value.getBitWidth());
1278 op, type, rewriter.getIntegerAttr(type, value));
1284 using OpConversionPattern::OpConversionPattern;
1287 matchAndRewrite(ConstantRealOp op, OpAdaptor adaptor,
1288 ConversionPatternRewriter &rewriter)
const override {
1289 rewriter.replaceOpWithNewOp<arith::ConstantOp>(op, op.getValueAttr());
1295 using OpConversionPattern::OpConversionPattern;
1298 matchAndRewrite(ConstantTimeOp op, OpAdaptor adaptor,
1299 ConversionPatternRewriter &rewriter)
const override {
1300 rewriter.replaceOpWithNewOp<llhd::ConstantTimeOp>(
1301 op, llhd::TimeAttr::get(op->getContext(), op.getValue(),
1302 StringRef(
"fs"), 0, 0));
1308 using OpConversionPattern::OpConversionPattern;
1310 matchAndRewrite(moore::ConstantStringOp op, OpAdaptor adaptor,
1311 ConversionPatternRewriter &rewriter)
const override {
1312 const auto resultType =
1313 typeConverter->convertType(op.getResult().getType());
1314 const auto intType = mlir::cast<IntegerType>(resultType);
1316 const auto str = op.getValue();
1317 const unsigned byteWidth = intType.getWidth();
1318 APInt value(byteWidth, 0);
1321 const size_t maxChars =
1322 std::min(str.size(),
static_cast<size_t>(byteWidth / 8));
1323 for (
size_t i = 0; i < maxChars; i++) {
1324 const size_t pos = str.size() - 1 - i;
1325 const auto asciiChar =
static_cast<uint8_t
>(str[pos]);
1326 value |= APInt(byteWidth, asciiChar) << (8 * i);
1330 op, resultType, rewriter.getIntegerAttr(resultType, value));
1336 using OpConversionPattern::OpConversionPattern;
1338 matchAndRewrite(ConcatOp op, OpAdaptor adaptor,
1339 ConversionPatternRewriter &rewriter)
const override {
1340 rewriter.replaceOpWithNewOp<
comb::ConcatOp>(op, adaptor.getValues());
1346 using OpConversionPattern::OpConversionPattern;
1348 matchAndRewrite(ReplicateOp op, OpAdaptor adaptor,
1349 ConversionPatternRewriter &rewriter)
const override {
1350 Type resultType = typeConverter->convertType(op.getResult().getType());
1352 rewriter.replaceOpWithNewOp<comb::ReplicateOp>(op, resultType,
1353 adaptor.getValue());
1359 using OpConversionPattern::OpConversionPattern;
1362 matchAndRewrite(ExtractOp op, OpAdaptor adaptor,
1363 ConversionPatternRewriter &rewriter)
const override {
1366 Type resultType = typeConverter->convertType(op.getResult().getType());
1367 Type inputType = adaptor.getInput().getType();
1368 int32_t low = adaptor.getLowBit();
1370 if (isa<IntegerType>(inputType)) {
1371 int32_t inputWidth = inputType.getIntOrFloatBitWidth();
1372 int32_t resultWidth = hw::getBitWidth(resultType);
1373 int32_t high = low + resultWidth;
1375 SmallVector<Value> toConcat;
1378 rewriter, op.getLoc(), APInt(std::min(-low, resultWidth), 0)));
1380 if (low < inputWidth && high > 0) {
1381 int32_t lowIdx = std::max(low, 0);
1384 rewriter.getIntegerType(
1385 std::min(resultWidth, std::min(high, inputWidth) - lowIdx)),
1386 adaptor.getInput(), lowIdx);
1387 toConcat.push_back(middle);
1390 int32_t diff = high - inputWidth;
1394 toConcat.push_back(val);
1399 rewriter.replaceOp(op, concat);
1403 if (
auto arrTy = dyn_cast<hw::ArrayType>(inputType)) {
1404 int32_t width = llvm::Log2_64_Ceil(arrTy.getNumElements());
1405 int32_t inputWidth = arrTy.getNumElements();
1407 if (
auto resArrTy = dyn_cast<hw::ArrayType>(resultType);
1408 resArrTy && resArrTy != arrTy.getElementType()) {
1409 int32_t elementWidth = hw::getBitWidth(arrTy.getElementType());
1410 if (elementWidth < 0)
1413 int32_t high = low + resArrTy.getNumElements();
1414 int32_t resWidth = resArrTy.getNumElements();
1416 SmallVector<Value> toConcat;
1419 rewriter, op.getLoc(),
1420 APInt(std::min((-low) * elementWidth, resWidth * elementWidth),
1423 op.getLoc(), hw::ArrayType::get(arrTy.getElementType(), -low),
1425 toConcat.push_back(res);
1428 if (low < inputWidth && high > 0) {
1429 int32_t lowIdx = std::max(0, low);
1431 rewriter, op.getLoc(), rewriter.getIntegerType(width), lowIdx);
1435 arrTy.getElementType(),
1436 std::min(resWidth, std::min(inputWidth, high) - lowIdx)),
1437 adaptor.getInput(), lowIdxVal);
1438 toConcat.push_back(middle);
1441 int32_t diff = high - inputWidth;
1444 rewriter, op.getLoc(), APInt(diff * elementWidth, 0));
1446 rewriter, op.getLoc(),
1447 hw::ArrayType::get(arrTy.getElementType(), diff), constZero);
1448 toConcat.push_back(val);
1453 rewriter.replaceOp(op, concat);
1458 if (low < 0 || low >= inputWidth) {
1459 int32_t bw = hw::getBitWidth(resultType);
1465 rewriter.createOrFold<
hw::BitcastOp>(op.getLoc(), resultType, val);
1466 rewriter.replaceOp(op, bitcast);
1471 rewriter.getIntegerType(width),
1472 adaptor.getLowBit());
1473 rewriter.replaceOpWithNewOp<
hw::ArrayGetOp>(op, adaptor.getInput(), idx);
1482 using OpConversionPattern::OpConversionPattern;
1485 matchAndRewrite(ExtractRefOp op, OpAdaptor adaptor,
1486 ConversionPatternRewriter &rewriter)
const override {
1488 Type resultType = typeConverter->convertType(op.getResult().getType());
1490 cast<llhd::RefType>(adaptor.getInput().getType()).getNestedType();
1492 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1493 int64_t width = hw::getBitWidth(inputType);
1498 rewriter, op.getLoc(),
1499 rewriter.getIntegerType(llvm::Log2_64_Ceil(width)),
1500 adaptor.getLowBit());
1501 rewriter.replaceOpWithNewOp<llhd::SigExtractOp>(
1502 op, resultType, adaptor.getInput(), lowBit);
1506 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1508 rewriter, op.getLoc(),
1509 rewriter.getIntegerType(llvm::Log2_64_Ceil(arrType.getNumElements())),
1510 adaptor.getLowBit());
1514 if (arrType.getElementType() !=
1515 cast<llhd::RefType>(resultType).getNestedType()) {
1516 rewriter.replaceOpWithNewOp<llhd::SigArraySliceOp>(
1517 op, resultType, adaptor.getInput(), lowBit);
1521 rewriter.replaceOpWithNewOp<llhd::SigArrayGetOp>(op, adaptor.getInput(),
1531 using OpConversionPattern::OpConversionPattern;
1534 matchAndRewrite(DynExtractOp op, OpAdaptor adaptor,
1535 ConversionPatternRewriter &rewriter)
const override {
1536 Type resultType = typeConverter->convertType(op.getResult().getType());
1537 Type inputType = adaptor.getInput().getType();
1539 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1540 Value amount = adjustIntegerWidth(rewriter, adaptor.getLowBit(),
1541 intType.getWidth(), op->getLoc());
1542 Value value = comb::ShrUOp::create(rewriter, op->getLoc(),
1543 adaptor.getInput(), amount);
1545 rewriter.replaceOpWithNewOp<
comb::ExtractOp>(op, resultType, value, 0);
1549 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1550 unsigned idxWidth = llvm::Log2_64_Ceil(arrType.getNumElements());
1551 Value idx = adjustIntegerWidth(rewriter, adaptor.getLowBit(), idxWidth,
1554 bool isSingleElementExtract = arrType.getElementType() == resultType;
1556 if (isSingleElementExtract)
1557 rewriter.replaceOpWithNewOp<
hw::ArrayGetOp>(op, adaptor.getInput(),
1561 adaptor.getInput(), idx);
1571 using OpConversionPattern::OpConversionPattern;
1574 matchAndRewrite(DynExtractRefOp op, OpAdaptor adaptor,
1575 ConversionPatternRewriter &rewriter)
const override {
1577 Type resultType = typeConverter->convertType(op.getResult().getType());
1579 cast<llhd::RefType>(adaptor.getInput().getType()).getNestedType();
1581 if (
auto intType = dyn_cast<IntegerType>(inputType)) {
1582 int64_t width = hw::getBitWidth(inputType);
1587 adjustIntegerWidth(rewriter, adaptor.getLowBit(),
1588 llvm::Log2_64_Ceil(width), op->getLoc());
1589 rewriter.replaceOpWithNewOp<llhd::SigExtractOp>(
1590 op, resultType, adaptor.getInput(), amount);
1594 if (
auto arrType = dyn_cast<hw::ArrayType>(inputType)) {
1595 Value idx = adjustIntegerWidth(
1596 rewriter, adaptor.getLowBit(),
1597 llvm::Log2_64_Ceil(arrType.getNumElements()), op->getLoc());
1599 auto resultNestedType = cast<llhd::RefType>(resultType).getNestedType();
1600 bool isSingleElementExtract =
1601 arrType.getElementType() == resultNestedType;
1603 if (isSingleElementExtract)
1604 rewriter.replaceOpWithNewOp<llhd::SigArrayGetOp>(op, adaptor.getInput(),
1607 rewriter.replaceOpWithNewOp<llhd::SigArraySliceOp>(
1608 op, resultType, adaptor.getInput(), idx);
1618 using OpConversionPattern::OpConversionPattern;
1621 matchAndRewrite(ArrayCreateOp op, OpAdaptor adaptor,
1622 ConversionPatternRewriter &rewriter)
const override {
1623 Type resultType = typeConverter->convertType(op.getResult().getType());
1625 adaptor.getElements());
1631 using OpConversionPattern::OpConversionPattern;
1634 matchAndRewrite(StructCreateOp op, OpAdaptor adaptor,
1635 ConversionPatternRewriter &rewriter)
const override {
1636 Type resultType = typeConverter->convertType(op.getResult().getType());
1638 adaptor.getFields());
1644 using OpConversionPattern::OpConversionPattern;
1647 matchAndRewrite(StructExtractOp op, OpAdaptor adaptor,
1648 ConversionPatternRewriter &rewriter)
const override {
1650 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1655struct StructExtractRefOpConversion
1657 using OpConversionPattern::OpConversionPattern;
1660 matchAndRewrite(StructExtractRefOp op, OpAdaptor adaptor,
1661 ConversionPatternRewriter &rewriter)
const override {
1662 rewriter.replaceOpWithNewOp<llhd::SigStructExtractOp>(
1663 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1669 using OpConversionPattern::OpConversionPattern;
1672 matchAndRewrite(UnionCreateOp op, OpAdaptor adaptor,
1673 ConversionPatternRewriter &rewriter)
const override {
1674 Type resultType = typeConverter->convertType(op.getResult().getType());
1675 rewriter.replaceOpWithNewOp<hw::UnionCreateOp>(
1676 op, resultType, adaptor.getFieldNameAttr(), adaptor.getInput());
1682 using OpConversionPattern::OpConversionPattern;
1685 matchAndRewrite(UnionExtractOp op, OpAdaptor adaptor,
1686 ConversionPatternRewriter &rewriter)
const override {
1687 rewriter.replaceOpWithNewOp<hw::UnionExtractOp>(op, adaptor.getInput(),
1688 adaptor.getFieldNameAttr());
1693struct UnionExtractRefOpConversion
1695 using OpConversionPattern::OpConversionPattern;
1698 matchAndRewrite(UnionExtractRefOp op, OpAdaptor adaptor,
1699 ConversionPatternRewriter &rewriter)
const override {
1700 rewriter.replaceOpWithNewOp<llhd::SigStructExtractOp>(
1701 op, adaptor.getInput(), adaptor.getFieldNameAttr());
1707 using OpConversionPattern::OpConversionPattern;
1709 matchAndRewrite(ReduceAndOp op, OpAdaptor adaptor,
1710 ConversionPatternRewriter &rewriter)
const override {
1711 Type resultType = typeConverter->convertType(op.getInput().getType());
1714 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::eq,
1715 adaptor.getInput(), max);
1721 using OpConversionPattern::OpConversionPattern;
1723 matchAndRewrite(ReduceOrOp op, OpAdaptor adaptor,
1724 ConversionPatternRewriter &rewriter)
const override {
1725 Type resultType = typeConverter->convertType(op.getInput().getType());
1728 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1729 adaptor.getInput(), zero);
1735 using OpConversionPattern::OpConversionPattern;
1737 matchAndRewrite(ReduceXorOp op, OpAdaptor adaptor,
1738 ConversionPatternRewriter &rewriter)
const override {
1740 rewriter.replaceOpWithNewOp<
comb::ParityOp>(op, adaptor.getInput());
1746 using OpConversionPattern::OpConversionPattern;
1748 matchAndRewrite(BoolCastOp op, OpAdaptor adaptor,
1749 ConversionPatternRewriter &rewriter)
const override {
1750 Type resultType = typeConverter->convertType(op.getInput().getType());
1751 if (isa_and_nonnull<IntegerType>(resultType)) {
1754 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1755 adaptor.getInput(), zero);
1758 if (isa_and_nonnull<FloatType>(resultType)) {
1759 Value zero = arith::ConstantOp::create(
1760 rewriter, op->getLoc(), rewriter.getFloatAttr(resultType, 0.0));
1761 rewriter.replaceOpWithNewOp<arith::CmpFOp>(op, arith::CmpFPredicate::ONE,
1762 adaptor.getInput(), zero);
1765 if (isa_and_nonnull<llhd::TimeType>(resultType)) {
1767 llhd::TimeToIntOp::create(rewriter, op->getLoc(), adaptor.getInput());
1769 rewriter.getI64Type(), 0);
1770 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1774 if (isa_and_nonnull<hw::StructType, hw::ArrayType, hw::UnionType>(
1776 int64_t width = hw::getBitWidth(resultType);
1779 auto intTy = rewriter.getIntegerType(width);
1780 Value input = rewriter.createOrFold<
hw::BitcastOp>(op->getLoc(), intTy,
1781 adaptor.getInput());
1783 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, comb::ICmpPredicate::ne,
1792 using OpConversionPattern::OpConversionPattern;
1794 matchAndRewrite(NotOp op, OpAdaptor adaptor,
1795 ConversionPatternRewriter &rewriter)
const override {
1797 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1800 rewriter.replaceOpWithNewOp<
comb::XorOp>(op, adaptor.getInput(), max);
1806 using OpConversionPattern::OpConversionPattern;
1808 matchAndRewrite(NegOp op, OpAdaptor adaptor,
1809 ConversionPatternRewriter &rewriter)
const override {
1811 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1814 rewriter.replaceOpWithNewOp<
comb::SubOp>(op, zero, adaptor.getInput());
1820 using OpConversionPattern::OpConversionPattern;
1822 matchAndRewrite(NegRealOp op, OpAdaptor adaptor,
1823 ConversionPatternRewriter &rewriter)
const override {
1824 rewriter.replaceOpWithNewOp<arith::NegFOp>(op, adaptor.getInput());
1829template <
typename SourceOp,
typename TargetOp>
1832 using OpAdaptor =
typename SourceOp::Adaptor;
1835 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1836 ConversionPatternRewriter &rewriter)
const override {
1837 rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(),
1838 adaptor.getRhs(),
false);
1843template <
typename SourceOp,
typename TargetOp>
1846 using OpAdaptor =
typename SourceOp::Adaptor;
1849 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1850 ConversionPatternRewriter &rewriter)
const override {
1851 rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(),
1857template <
typename SourceOp, ICmpPredicate pred>
1860 using OpAdaptor =
typename SourceOp::Adaptor;
1863 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1864 ConversionPatternRewriter &rewriter)
const override {
1866 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1868 rewriter.replaceOpWithNewOp<comb::ICmpOp>(
1869 op, resultType, pred, adaptor.getLhs(), adaptor.getRhs());
1874template <
typename SourceOp, arith::CmpFPredicate pred>
1877 using OpAdaptor =
typename SourceOp::Adaptor;
1880 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1881 ConversionPatternRewriter &rewriter)
const override {
1883 ConversionPattern::typeConverter->convertType(op.getResult().getType());
1885 rewriter.replaceOpWithNewOp<arith::CmpFOp>(
1886 op, resultType, pred, adaptor.getLhs(), adaptor.getRhs());
1891template <
typename SourceOp,
bool withoutX>
1894 using OpAdaptor =
typename SourceOp::Adaptor;
1897 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1898 ConversionPatternRewriter &rewriter)
const override {
1904 unsigned bitWidth = op.getLhs().getType().getWidth();
1905 auto ignoredBits = APInt::getZero(bitWidth);
1906 auto detectIgnoredBits = [&](Value value) {
1907 auto constOp = value.getDefiningOp<ConstantOp>();
1910 auto constValue = constOp.getValue();
1912 ignoredBits |= constValue.getZBits();
1914 ignoredBits |= constValue.getUnknownBits();
1916 detectIgnoredBits(op.getLhs());
1917 detectIgnoredBits(op.getRhs());
1921 Value lhs = adaptor.getLhs();
1922 Value rhs = adaptor.getRhs();
1923 if (!ignoredBits.isZero()) {
1924 ignoredBits.flipAllBits();
1926 lhs = rewriter.createOrFold<
comb::AndOp>(op.getLoc(), lhs, maskOp);
1927 rhs = rewriter.createOrFold<
comb::AndOp>(op.getLoc(), rhs, maskOp);
1930 rewriter.replaceOpWithNewOp<comb::ICmpOp>(op, ICmpPredicate::ceq, lhs, rhs);
1940 using OpConversionPattern::OpConversionPattern;
1943 matchAndRewrite(ConversionOp op, OpAdaptor adaptor,
1944 ConversionPatternRewriter &rewriter)
const override {
1945 Location loc = op.getLoc();
1946 Type resultType = typeConverter->convertType(op.getResult().getType());
1948 op.emitError(
"conversion result type is not currently supported");
1951 int64_t inputBw = hw::getBitWidth(adaptor.getInput().getType());
1952 int64_t resultBw = hw::getBitWidth(resultType);
1953 if (inputBw == -1 || resultBw == -1) {
1954 if (isSupportedDpiOpenArrayCast(op.getInput().getType(),
1955 op.getResult().getType())) {
1956 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
1957 op, resultType, adaptor.getInput());
1960 if (hasOpenArrayBoundaryType(op.getInput().getType()) ||
1961 hasOpenArrayBoundaryType(op.getResult().getType())) {
1962 op.emitError(
"unsupported DPI open-array conversion from ")
1963 << op.getInput().getType() <<
" to " << op.getResult().getType();
1970 loc, rewriter.getIntegerType(inputBw), adaptor.getInput());
1971 Value amount = adjustIntegerWidth(rewriter, input, resultBw, loc);
1974 rewriter.createOrFold<
hw::BitcastOp>(loc, resultType, amount);
1975 rewriter.replaceOp(op, result);
1980template <
typename SourceOp>
1983 using OpAdaptor =
typename SourceOp::Adaptor;
1984 using ConversionPattern::typeConverter;
1987 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
1988 ConversionPatternRewriter &rewriter)
const override {
1989 auto type = typeConverter->convertType(op.getResult().getType());
1990 if (type == adaptor.getInput().getType())
1991 rewriter.replaceOp(op, adaptor.getInput());
1993 rewriter.replaceOpWithNewOp<
hw::BitcastOp>(op, type, adaptor.getInput());
1999template <
typename SourceOp>
2002 using OpAdaptor =
typename SourceOp::Adaptor;
2003 using ConversionPattern::typeConverter;
2006 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
2007 ConversionPatternRewriter &rewriter)
const override {
2008 rewriter.replaceOp(op, adaptor.getInput());
2014 using OpConversionPattern::OpConversionPattern;
2017 matchAndRewrite(TruncOp op, OpAdaptor adaptor,
2018 ConversionPatternRewriter &rewriter)
const override {
2019 rewriter.replaceOpWithNewOp<
comb::ExtractOp>(op, adaptor.getInput(), 0,
2020 op.getType().getWidth());
2026 using OpConversionPattern::OpConversionPattern;
2029 matchAndRewrite(ZExtOp op, OpAdaptor adaptor,
2030 ConversionPatternRewriter &rewriter)
const override {
2031 auto targetWidth = op.getType().getWidth();
2032 auto inputWidth = op.getInput().getType().getWidth();
2035 rewriter, op.getLoc(),
2036 rewriter.getIntegerType(targetWidth - inputWidth), 0);
2039 op, ValueRange{zeroExt, adaptor.getInput()});
2045 using OpConversionPattern::OpConversionPattern;
2048 matchAndRewrite(SExtOp op, OpAdaptor adaptor,
2049 ConversionPatternRewriter &rewriter)
const override {
2050 auto type = typeConverter->convertType(op.getType());
2052 comb::createOrFoldSExt(rewriter, op.getLoc(), adaptor.getInput(), type);
2053 rewriter.replaceOp(op, value);
2059 using OpConversionPattern::OpConversionPattern;
2062 matchAndRewrite(SIntToRealOp op, OpAdaptor adaptor,
2063 ConversionPatternRewriter &rewriter)
const override {
2064 rewriter.replaceOpWithNewOp<arith::SIToFPOp>(
2065 op, typeConverter->convertType(op.getType()), adaptor.getInput());
2071 using OpConversionPattern::OpConversionPattern;
2074 matchAndRewrite(UIntToRealOp op, OpAdaptor adaptor,
2075 ConversionPatternRewriter &rewriter)
const override {
2076 rewriter.replaceOpWithNewOp<arith::UIToFPOp>(
2077 op, typeConverter->convertType(op.getType()), adaptor.getInput());
2083 using OpConversionPattern::OpConversionPattern;
2086 matchAndRewrite(IntToStringOp op, OpAdaptor adaptor,
2087 ConversionPatternRewriter &rewriter)
const override {
2088 rewriter.replaceOpWithNewOp<sim::IntToStringOp>(op, adaptor.getInput());
2093struct FormatStringToStringOpConversion
2095 using OpConversionPattern::OpConversionPattern;
2098 matchAndRewrite(FormatStringToStringOp op, OpAdaptor adaptor,
2099 ConversionPatternRewriter &rewriter)
const override {
2100 rewriter.replaceOpWithNewOp<sim::FormatToStringOp>(op,
2101 adaptor.getFmtstring());
2107 using OpConversionPattern::OpConversionPattern;
2110 matchAndRewrite(RealToIntOp op, OpAdaptor adaptor,
2111 ConversionPatternRewriter &rewriter)
const override {
2112 rewriter.replaceOpWithNewOp<arith::FPToSIOp>(
2113 op, typeConverter->convertType(op.getType()), adaptor.getInput());
2119 using OpConversionPattern::OpConversionPattern;
2122 matchAndRewrite(ConvertRealOp op, OpAdaptor adaptor,
2123 ConversionPatternRewriter &rewriter)
const override {
2124 op.getInput().getType().getWidth() < op.getResult().getType().getWidth()
2125 ? rewriter.replaceOpWithNewOp<arith::ExtFOp>(
2126 op, typeConverter->convertType(op.getType()), adaptor.getInput())
2127 : rewriter.replaceOpWithNewOp<arith::TruncFOp>(
2128 op, typeConverter->
convertType(op.getType()), adaptor.getInput());
2138 using OpConversionPattern::OpConversionPattern;
2141 matchAndRewrite(hw::InstanceOp op, OpAdaptor adaptor,
2142 ConversionPatternRewriter &rewriter)
const override {
2143 SmallVector<Type> convResTypes;
2144 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
2147 rewriter.replaceOpWithNewOp<hw::InstanceOp>(
2148 op, convResTypes, op.getInstanceName(), op.getModuleName(),
2149 adaptor.getOperands(), op.getArgNames(),
2150 op.getResultNames(),
2151 rewriter.getArrayAttr({}),
nullptr);
2158 using OpConversionPattern::OpConversionPattern;
2161 matchAndRewrite(func::ReturnOp op, OpAdaptor adaptor,
2162 ConversionPatternRewriter &rewriter)
const override {
2163 rewriter.replaceOpWithNewOp<func::ReturnOp>(op, adaptor.getOperands());
2169 using OpConversionPattern::OpConversionPattern;
2172 matchAndRewrite(func::CallOp op, OpAdaptor adaptor,
2173 ConversionPatternRewriter &rewriter)
const override {
2174 SmallVector<Type> convResTypes;
2175 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
2177 rewriter.replaceOpWithNewOp<func::CallOp>(
2178 op, adaptor.getCallee(), convResTypes, adaptor.getOperands());
2183struct FuncDPICallOpConversion
2185 using OpConversionPattern::OpConversionPattern;
2188 matchAndRewrite(moore::FuncDPICallOp op, OpAdaptor adaptor,
2189 ConversionPatternRewriter &rewriter)
const override {
2190 SmallVector<Type> convResTypes;
2191 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
2193 rewriter.replaceOpWithNewOp<sim::DPICallOp>(
2194 op, convResTypes, op.getCalleeAttr(), Value(),
2195 Value(), adaptor.getInputs());
2201 using OpConversionPattern::OpConversionPattern;
2204 matchAndRewrite(moore::DPIFuncOp op, OpAdaptor adaptor,
2205 ConversionPatternRewriter &rewriter)
const override {
2207 auto toDPIDir = [](moore::DPIArgDirection dir) -> sim::DPIDirection {
2209 case moore::DPIArgDirection::In:
2210 return sim::DPIDirection::Input;
2211 case moore::DPIArgDirection::Out:
2212 return sim::DPIDirection::Output;
2213 case moore::DPIArgDirection::InOut:
2214 return sim::DPIDirection::InOut;
2215 case moore::DPIArgDirection::Return:
2216 return sim::DPIDirection::Return;
2218 llvm_unreachable(
"unknown DPIArgDirection");
2222 auto dirs = op.getDpiArgDirs();
2223 auto names = op.getDpiArgNames();
2224 SmallVector<Type> argTypes;
2225 op.getDPIArgTypes(argTypes);
2227 SmallVector<sim::DPIArgument> dpiArguments;
2228 for (
auto [dirAttr, nameAttr, mooreType] :
2229 llvm::zip(dirs, names, argTypes)) {
2230 auto dir = toDPIDir(cast<moore::DPIArgDirectionAttr>(dirAttr).getValue());
2231 auto name = cast<StringAttr>(nameAttr);
2232 Type coreType = typeConverter->convertType(mooreType);
2234 return op.emitOpError(
"argument '")
2235 << name <<
"' has unsupported type " << mooreType;
2236 dpiArguments.push_back({name, coreType, dir});
2239 auto coreDPIFuncType =
2240 sim::DPIFunctionType::get(rewriter.getContext(), dpiArguments);
2241 auto simFunc = sim::DPIFuncOp::create(
2242 rewriter, op.getLoc(), op.getSymNameAttr(), coreDPIFuncType,
2243 op.getArgumentLocsAttr(), op.getVerilogNameAttr());
2244 SymbolTable::setSymbolVisibility(simFunc,
2245 SymbolTable::getSymbolVisibility(op));
2246 rewriter.eraseOp(op);
2251struct UnrealizedConversionCastConversion
2253 using OpConversionPattern::OpConversionPattern;
2256 matchAndRewrite(UnrealizedConversionCastOp op, OpAdaptor adaptor,
2257 ConversionPatternRewriter &rewriter)
const override {
2258 SmallVector<Type> convResTypes;
2259 if (typeConverter->convertTypes(op.getResultTypes(), convResTypes).failed())
2264 if (convResTypes == adaptor.getOperands().getTypes()) {
2265 rewriter.replaceOp(op, adaptor.getOperands());
2269 rewriter.replaceOpWithNewOp<UnrealizedConversionCastOp>(
2270 op, convResTypes, adaptor.getOperands());
2276 using OpConversionPattern::OpConversionPattern;
2279 matchAndRewrite(ShlOp op, OpAdaptor adaptor,
2280 ConversionPatternRewriter &rewriter)
const override {
2281 Type resultType = typeConverter->convertType(op.getResult().getType());
2285 adjustIntegerWidth(rewriter, adaptor.getAmount(),
2286 resultType.getIntOrFloatBitWidth(), op->getLoc());
2287 rewriter.replaceOpWithNewOp<
comb::ShlOp>(op, resultType, adaptor.getValue(),
2294 using OpConversionPattern::OpConversionPattern;
2297 matchAndRewrite(ShrOp op, OpAdaptor adaptor,
2298 ConversionPatternRewriter &rewriter)
const override {
2299 Type resultType = typeConverter->convertType(op.getResult().getType());
2303 adjustIntegerWidth(rewriter, adaptor.getAmount(),
2304 resultType.getIntOrFloatBitWidth(), op->getLoc());
2306 op, resultType, adaptor.getValue(), amount,
false);
2312 using OpConversionPattern::OpConversionPattern;
2315 matchAndRewrite(PowUOp op, OpAdaptor adaptor,
2316 ConversionPatternRewriter &rewriter)
const override {
2317 Type resultType = typeConverter->convertType(op.getResult().getType());
2319 Location loc = op->getLoc();
2324 auto lhs = comb::ConcatOp::create(rewriter, loc, zeroVal, adaptor.getLhs());
2325 auto rhs = comb::ConcatOp::create(rewriter, loc, zeroVal, adaptor.getRhs());
2328 auto pow = mlir::math::IPowIOp::create(rewriter, loc, lhs, rhs);
2336 using OpConversionPattern::OpConversionPattern;
2339 matchAndRewrite(PowSOp op, OpAdaptor adaptor,
2340 ConversionPatternRewriter &rewriter)
const override {
2341 Type resultType = typeConverter->convertType(op.getResult().getType());
2345 rewriter.replaceOpWithNewOp<mlir::math::IPowIOp>(
2346 op, resultType, adaptor.getLhs(), adaptor.getRhs());
2352 using OpConversionPattern::OpConversionPattern;
2355 matchAndRewrite(AShrOp op, OpAdaptor adaptor,
2356 ConversionPatternRewriter &rewriter)
const override {
2357 Type resultType = typeConverter->convertType(op.getResult().getType());
2361 adjustIntegerWidth(rewriter, adaptor.getAmount(),
2362 resultType.getIntOrFloatBitWidth(), op->getLoc());
2364 op, resultType, adaptor.getValue(), amount,
false);
2370 using OpConversionPattern::OpConversionPattern;
2373 matchAndRewrite(ReadOp op, OpAdaptor adaptor,
2374 ConversionPatternRewriter &rewriter)
const override {
2375 rewriter.replaceOpWithNewOp<llhd::ProbeOp>(op, adaptor.getInput());
2380struct AssignedVariableOpConversion
2382 using OpConversionPattern::OpConversionPattern;
2385 matchAndRewrite(AssignedVariableOp op, OpAdaptor adaptor,
2386 ConversionPatternRewriter &rewriter)
const override {
2387 rewriter.replaceOpWithNewOp<hw::WireOp>(op, adaptor.getInput(),
2388 adaptor.getNameAttr());
2394static llhd::TimeAttr
2395getBlockingOrContinuousAssignDelay(mlir::MLIRContext *
context) {
2396 return llhd::TimeAttr::get(
context, 0U,
"ns", 0, 1);
2399template <
typename OpTy>
2402 using OpAdaptor =
typename OpTy::Adaptor;
2405 matchAndRewrite(OpTy op, OpAdaptor adaptor,
2406 ConversionPatternRewriter &rewriter)
const override {
2409 if constexpr (std::is_same_v<OpTy, ContinuousAssignOp> ||
2410 std::is_same_v<OpTy, BlockingAssignOp>) {
2411 delay = llhd::ConstantTimeOp::create(
2412 rewriter, op->getLoc(),
2413 getBlockingOrContinuousAssignDelay(op->getContext()));
2414 }
else if constexpr (std::is_same_v<OpTy, NonBlockingAssignOp>) {
2416 delay = llhd::ConstantTimeOp::create(
2417 rewriter, op->getLoc(),
2418 llhd::TimeAttr::get(op->getContext(), 0U,
"ns", 1, 0));
2421 delay = adaptor.getDelay();
2424 rewriter.replaceOpWithNewOp<llhd::DriveOp>(
2425 op, adaptor.getDst(), adaptor.getSrc(), delay, Value{});
2431 using OpConversionPattern::OpConversionPattern;
2434 matchAndRewrite(ConditionalOp op, OpAdaptor adaptor,
2435 ConversionPatternRewriter &rewriter)
const override {
2440 auto type = typeConverter->convertType(op.getType());
2442 auto hasNoWriteEffect = [](Region ®ion) {
2443 auto result = region.walk([](Operation *operation) {
2444 if (
auto memOp = dyn_cast<MemoryEffectOpInterface>(operation))
2445 if (!memOp.hasEffect<MemoryEffects::Write>() &&
2446 !memOp.hasEffect<MemoryEffects::Free>())
2447 return WalkResult::advance();
2449 if (operation->hasTrait<OpTrait::HasRecursiveMemoryEffects>())
2450 return WalkResult::advance();
2452 return WalkResult::interrupt();
2454 return !result.wasInterrupted();
2457 if (hasNoWriteEffect(op.getTrueRegion()) &&
2458 hasNoWriteEffect(op.getFalseRegion())) {
2459 Operation *trueTerm = op.getTrueRegion().front().getTerminator();
2460 Operation *falseTerm = op.getFalseRegion().front().getTerminator();
2462 rewriter.inlineBlockBefore(&op.getTrueRegion().front(), op);
2463 rewriter.inlineBlockBefore(&op.getFalseRegion().front(), op);
2465 Value convTrueVal = typeConverter->materializeTargetConversion(
2466 rewriter, op.getLoc(), type, trueTerm->getOperand(0));
2467 Value convFalseVal = typeConverter->materializeTargetConversion(
2468 rewriter, op.getLoc(), type, falseTerm->getOperand(0));
2470 rewriter.eraseOp(trueTerm);
2471 rewriter.eraseOp(falseTerm);
2473 rewriter.replaceOpWithNewOp<
comb::MuxOp>(op, adaptor.getCondition(),
2474 convTrueVal, convFalseVal);
2479 scf::IfOp::create(rewriter, op.getLoc(), type, adaptor.getCondition());
2480 rewriter.inlineRegionBefore(op.getTrueRegion(), ifOp.getThenRegion(),
2481 ifOp.getThenRegion().end());
2482 rewriter.inlineRegionBefore(op.getFalseRegion(), ifOp.getElseRegion(),
2483 ifOp.getElseRegion().end());
2484 rewriter.replaceOp(op, ifOp);
2490 using OpConversionPattern::OpConversionPattern;
2493 matchAndRewrite(YieldOp op, OpAdaptor adaptor,
2494 ConversionPatternRewriter &rewriter)
const override {
2495 Operation *parent = op->getParentOp();
2496 if (isa<llhd::GlobalSignalOp>(parent))
2497 rewriter.replaceOpWithNewOp<llhd::YieldOp>(op, adaptor.getResult());
2498 else if (isa<scf::ExecuteRegionOp, scf::ForOp, scf::IfOp,
2499 scf::IndexSwitchOp, scf::WhileOp>(parent))
2500 rewriter.replaceOpWithNewOp<scf::YieldOp>(op, adaptor.getResult());
2502 return rewriter.notifyMatchFailure(
2503 op,
"yield parent has not been converted to a legal region op yet");
2508template <
typename SourceOp>
2511 using OpAdaptor =
typename SourceOp::Adaptor;
2514 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
2515 ConversionPatternRewriter &rewriter)
const override {
2516 rewriter.modifyOpInPlace(op,
2517 [&]() { op->setOperands(adaptor.getOperands()); });
2522template <
typename MooreOpTy,
typename VerifOpTy>
2525 using OpAdaptor =
typename MooreOpTy::Adaptor;
2528 matchAndRewrite(MooreOpTy op, OpAdaptor adaptor,
2529 ConversionPatternRewriter &rewriter)
const override {
2531 op.getLabel().has_value()
2532 ? StringAttr::get(op->getContext(), op.getLabel().value())
2533 : StringAttr::
get(op->getContext());
2534 rewriter.replaceOpWithNewOp<VerifOpTy>(op, adaptor.getCond(), mlir::Value(),
2545 using OpConversionPattern::OpConversionPattern;
2548 matchAndRewrite(FormatLiteralOp op, OpAdaptor adaptor,
2549 ConversionPatternRewriter &rewriter)
const override {
2550 rewriter.replaceOpWithNewOp<sim::FormatLiteralOp>(op, adaptor.getLiteral());
2556 using OpConversionPattern::OpConversionPattern;
2559 matchAndRewrite(FormatStringOp op, OpAdaptor adaptor,
2560 ConversionPatternRewriter &rewriter)
const override {
2562 op.getPadding().value_or(IntPadding::Space) == IntPadding::Space ? 32
2564 IntegerAttr padCharAttr = rewriter.getI8IntegerAttr(padChar);
2565 auto widthAttr = adaptor.getWidthAttr();
2567 bool isLeftAligned =
2568 op.getAlignment().value_or(IntAlign::Right) == IntAlign::Left;
2569 BoolAttr isLeftAlignedAttr = rewriter.getBoolAttr(isLeftAligned);
2571 rewriter.replaceOpWithNewOp<sim::FormatStringOp>(
2572 op, adaptor.getString(), isLeftAlignedAttr, padCharAttr, widthAttr);
2578 using OpConversionPattern::OpConversionPattern;
2581 matchAndRewrite(FormatConcatOp op, OpAdaptor adaptor,
2582 ConversionPatternRewriter &rewriter)
const override {
2583 rewriter.replaceOpWithNewOp<sim::FormatStringConcatOp>(op,
2584 adaptor.getInputs());
2589struct FormatHierPathOpConversion
2591 using OpConversionPattern::OpConversionPattern;
2594 matchAndRewrite(FormatHierPathOp op, OpAdaptor adaptor,
2595 ConversionPatternRewriter &rewriter)
const override {
2596 rewriter.replaceOpWithNewOp<sim::FormatHierPathOp>(op,
2597 adaptor.getUseEscapes());
2603 using OpConversionPattern::OpConversionPattern;
2606 matchAndRewrite(FormatIntOp op, OpAdaptor adaptor,
2607 ConversionPatternRewriter &rewriter)
const override {
2609 char padChar = adaptor.getPadding() == IntPadding::Space ? 32 : 48;
2610 IntegerAttr padCharAttr = rewriter.getI8IntegerAttr(padChar);
2611 auto widthAttr = adaptor.getSpecifierWidthAttr();
2613 bool isLeftAligned = adaptor.getAlignment() == IntAlign::Left;
2614 BoolAttr isLeftAlignedAttr = rewriter.getBoolAttr(isLeftAligned);
2616 switch (op.getFormat()) {
2617 case IntFormat::Decimal:
2618 rewriter.replaceOpWithNewOp<sim::FormatDecOp>(
2619 op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr,
2620 adaptor.getIsSignedAttr());
2622 case IntFormat::Binary:
2623 rewriter.replaceOpWithNewOp<sim::FormatBinOp>(
2624 op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr);
2626 case IntFormat::Octal:
2627 rewriter.replaceOpWithNewOp<sim::FormatOctOp>(
2628 op, adaptor.getValue(), isLeftAlignedAttr, padCharAttr, widthAttr);
2630 case IntFormat::HexLower:
2631 rewriter.replaceOpWithNewOp<sim::FormatHexOp>(
2632 op, adaptor.getValue(), rewriter.getBoolAttr(
false),
2633 isLeftAlignedAttr, padCharAttr, widthAttr);
2635 case IntFormat::HexUpper:
2636 rewriter.replaceOpWithNewOp<sim::FormatHexOp>(
2637 op, adaptor.getValue(), rewriter.getBoolAttr(
true), isLeftAlignedAttr,
2638 padCharAttr, widthAttr);
2641 return rewriter.notifyMatchFailure(op,
"unsupported int format");
2646 using OpConversionPattern::OpConversionPattern;
2649 matchAndRewrite(FormatRealOp op, OpAdaptor adaptor,
2650 ConversionPatternRewriter &rewriter)
const override {
2651 auto fracDigitsAttr = adaptor.getFracDigitsAttr();
2653 auto fieldWidthAttr = adaptor.getFieldWidthAttr();
2654 bool isLeftAligned = adaptor.getAlignment() == IntAlign::Left;
2655 mlir::BoolAttr isLeftAlignedAttr = rewriter.getBoolAttr(isLeftAligned);
2657 switch (op.getFormat()) {
2658 case RealFormat::General:
2659 rewriter.replaceOpWithNewOp<sim::FormatGeneralOp>(
2660 op, adaptor.getValue(), isLeftAlignedAttr, fieldWidthAttr,
2663 case RealFormat::Float:
2664 rewriter.replaceOpWithNewOp<sim::FormatFloatOp>(
2665 op, adaptor.getValue(), isLeftAlignedAttr, fieldWidthAttr,
2668 case RealFormat::Exponential:
2669 rewriter.replaceOpWithNewOp<sim::FormatScientificOp>(
2670 op, adaptor.getValue(), isLeftAlignedAttr, fieldWidthAttr,
2677struct FormatCharOpConversion
2679 using OpConversionPattern::OpConversionPattern;
2681 matchAndRewrite(moore::FormatCharOp op, OpAdaptor adaptor,
2682 ConversionPatternRewriter &rewriter)
const override {
2683 rewriter.replaceOpWithNewOp<sim::FormatCharOp>(op, adaptor.getValue());
2689 using OpConversionPattern::OpConversionPattern;
2692 matchAndRewrite(StringLenOp op, OpAdaptor adaptor,
2693 ConversionPatternRewriter &rewriter)
const override {
2694 rewriter.replaceOpWithNewOp<sim::StringLengthOp>(op, adaptor.getStr());
2700 using OpConversionPattern::OpConversionPattern;
2703 matchAndRewrite(StringConcatOp op, OpAdaptor adaptor,
2704 ConversionPatternRewriter &rewriter)
const override {
2705 rewriter.replaceOpWithNewOp<sim::StringConcatOp>(op, adaptor.getInputs());
2711 using OpConversionPattern::OpConversionPattern;
2714 matchAndRewrite(StringGetOp op, OpAdaptor adaptor,
2715 ConversionPatternRewriter &rewriter)
const override {
2716 rewriter.replaceOpWithNewOp<sim::StringGetOp>(op, adaptor.getStr(),
2717 adaptor.getIndex());
2723 using OpConversionPattern::OpConversionPattern;
2726 matchAndRewrite(QueueSizeBIOp op, OpAdaptor adaptor,
2727 ConversionPatternRewriter &rewriter)
const override {
2728 rewriter.replaceOpWithNewOp<sim::QueueSizeOp>(op, adaptor.getQueue());
2733struct DynQueueExtractOpConversion
2735 using OpConversionPattern::OpConversionPattern;
2738 matchAndRewrite(DynQueueExtractOp op, OpAdaptor adaptor,
2739 ConversionPatternRewriter &rewriter)
const override {
2740 bool isSingleElementExtract =
2741 op.getInput().getType().getElementType() == op.getResult().getType();
2743 if (isSingleElementExtract) {
2744 rewriter.replaceOpWithNewOp<sim::QueueGetOp>(op, adaptor.getInput(),
2745 adaptor.getLowerIdx());
2747 rewriter.replaceOpWithNewOp<sim::QueueSliceOp>(
2748 op, adaptor.getInput(), adaptor.getLowerIdx(), adaptor.getUpperIdx());
2764probeRefAndDriveWithResult(OpBuilder &builder, Location loc, Value ref,
2765 const std::function<Value(Value)> &func) {
2767 Value v = llhd::ProbeOp::create(builder, loc, ref);
2770 Value delay = llhd::ConstantTimeOp::create(
2771 builder, loc, getBlockingOrContinuousAssignDelay(builder.getContext()));
2773 llhd::DriveOp::create(builder, loc, ref, func(v), delay, Value{});
2777 using OpConversionPattern::OpConversionPattern;
2780 matchAndRewrite(QueuePushBackOp op, OpAdaptor adaptor,
2781 ConversionPatternRewriter &rewriter)
const override {
2782 probeRefAndDriveWithResult(
2783 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2784 return sim::QueuePushBackOp::create(rewriter, op->getLoc(), queue,
2785 adaptor.getElement());
2788 rewriter.eraseOp(op);
2793struct QueuePushFrontOpConversion
2795 using OpConversionPattern::OpConversionPattern;
2798 matchAndRewrite(QueuePushFrontOp op, OpAdaptor adaptor,
2799 ConversionPatternRewriter &rewriter)
const override {
2801 probeRefAndDriveWithResult(
2802 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2803 return sim::QueuePushFrontOp::create(rewriter, op->getLoc(), queue,
2804 adaptor.getElement());
2807 rewriter.eraseOp(op);
2813 using OpConversionPattern::OpConversionPattern;
2816 matchAndRewrite(QueuePopBackOp op, OpAdaptor adaptor,
2817 ConversionPatternRewriter &rewriter)
const override {
2819 probeRefAndDriveWithResult(
2820 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2822 sim::QueuePopBackOp::create(rewriter, op->getLoc(), queue);
2823 popped = popBack.getPopped();
2824 return popBack.getOutQueue();
2826 rewriter.replaceOp(op, popped);
2833 using OpConversionPattern::OpConversionPattern;
2836 matchAndRewrite(QueuePopFrontOp op, OpAdaptor adaptor,
2837 ConversionPatternRewriter &rewriter)
const override {
2839 probeRefAndDriveWithResult(
2840 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2842 sim::QueuePopFrontOp::create(rewriter, op->getLoc(), queue);
2843 popped = popFront.getPopped();
2844 return popFront.getOutQueue();
2846 rewriter.replaceOp(op, popped);
2853 using OpConversionPattern::OpConversionPattern;
2856 matchAndRewrite(QueueClearOp op, OpAdaptor adaptor,
2857 ConversionPatternRewriter &rewriter)
const override {
2858 auto refType = cast<llhd::RefType>(adaptor.getQueue().getType());
2859 auto queueType = refType.getNestedType();
2861 sim::QueueEmptyOp::create(rewriter, op->getLoc(), queueType);
2864 Value delay = llhd::ConstantTimeOp::create(
2865 rewriter, op.getLoc(),
2866 getBlockingOrContinuousAssignDelay(rewriter.getContext()));
2868 llhd::DriveOp::create(rewriter, op.getLoc(), adaptor.getQueue(), emptyQueue,
2871 rewriter.eraseOp(op);
2877 using OpConversionPattern::OpConversionPattern;
2880 matchAndRewrite(QueueInsertOp op, OpAdaptor adaptor,
2881 ConversionPatternRewriter &rewriter)
const override {
2882 probeRefAndDriveWithResult(
2883 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2885 sim::QueueInsertOp::create(rewriter, op->getLoc(), queue,
2886 adaptor.getIndex(), adaptor.getItem());
2888 return insert.getOutQueue();
2890 rewriter.eraseOp(op);
2897 using OpConversionPattern::OpConversionPattern;
2900 matchAndRewrite(QueueDeleteOp op, OpAdaptor adaptor,
2901 ConversionPatternRewriter &rewriter)
const override {
2902 probeRefAndDriveWithResult(
2903 rewriter, op.getLoc(), adaptor.getQueue(), [&](Value queue) {
2904 auto delOp = sim::QueueDeleteOp::create(rewriter, op->getLoc(), queue,
2905 adaptor.getIndex());
2907 return delOp.getOutQueue();
2909 rewriter.eraseOp(op);
2916 using OpConversionPattern::OpConversionPattern;
2919 matchAndRewrite(QueueResizeOp op, OpAdaptor adaptor,
2920 ConversionPatternRewriter &rewriter)
const override {
2922 rewriter.replaceOpWithNewOp<sim::QueueResizeOp>(
2923 op, getTypeConverter()->convertType(op.getResult().getType()),
2924 adaptor.getInput());
2930 using OpConversionPattern::OpConversionPattern;
2932 matchAndRewrite(QueueSetOp op, OpAdaptor adaptor,
2933 ConversionPatternRewriter &rewriter)
const override {
2934 probeRefAndDriveWithResult(
2935 rewriter, op->getLoc(), adaptor.getQueue(), [&](Value queue) {
2937 sim::QueueSetOp::create(rewriter, op.getLoc(), queue,
2938 adaptor.getIndex(), adaptor.getItem());
2939 return setOp.getOutQueue();
2941 rewriter.eraseOp(op);
2947 using OpConversionPattern::OpConversionPattern;
2950 matchAndRewrite(QueueCmpOp op, OpAdaptor adaptor,
2951 ConversionPatternRewriter &rewriter)
const override {
2959 auto unpackedPred = adaptor.getPredicateAttr().getValue();
2960 sim::QueueCmpPredicate queuePred;
2961 switch (unpackedPred) {
2962 case circt::moore::UArrayCmpPredicate::eq:
2963 queuePred = sim::QueueCmpPredicate::eq;
2965 case circt::moore::UArrayCmpPredicate::ne:
2966 queuePred = sim::QueueCmpPredicate::ne;
2970 auto cmpPred = sim::QueueCmpPredicateAttr::get(getContext(), queuePred);
2972 rewriter.replaceOpWithNewOp<sim::QueueCmpOp>(op, cmpPred, adaptor.getLhs(),
2978struct QueueFromUnpackedArrayOpConversion
2980 using OpConversionPattern::OpConversionPattern;
2983 matchAndRewrite(QueueFromUnpackedArrayOp op, OpAdaptor adaptor,
2984 ConversionPatternRewriter &rewriter)
const override {
2985 rewriter.replaceOpWithNewOp<sim::QueueFromArrayOp>(
2986 op, getTypeConverter()->convertType(op.getResult().getType()),
2987 adaptor.getInput());
2993 using OpConversionPattern::OpConversionPattern;
2996 matchAndRewrite(QueueConcatOp op, OpAdaptor adaptor,
2997 ConversionPatternRewriter &rewriter)
const override {
2998 rewriter.replaceOpWithNewOp<sim::QueueConcatOp>(
2999 op, getTypeConverter()->convertType(op.getResult().getType()),
3000 adaptor.getInputs());
3006 using OpConversionPattern::OpConversionPattern;
3009 matchAndRewrite(DisplayBIOp op, OpAdaptor adaptor,
3010 ConversionPatternRewriter &rewriter)
const override {
3011 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(
3012 op, adaptor.getMessage());
3018 using OpConversionPattern::OpConversionPattern;
3020 matchAndRewrite(FDisplayBIOp op, OpAdaptor adaptor,
3021 ConversionPatternRewriter &rewriter)
const override {
3022 auto stream = sim::SVChannelToOutputStreamOp::create(rewriter, op.getLoc(),
3024 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(
3025 op, adaptor.getMessage(), stream.getStream());
3031 using OpConversionPattern::OpConversionPattern;
3033 matchAndRewrite(FOpenBIOp op, OpAdaptor adaptor,
3034 ConversionPatternRewriter &rewriter)
const override {
3035 sim::SVFOpenModeAttr simMode;
3036 if (
auto modeAttr = op.getModeAttr()) {
3037 auto mapMode = [](moore::FOpenMode m) -> sim::SVFOpenMode {
3039 case moore::FOpenMode::Read:
3040 return sim::SVFOpenMode::Read;
3041 case moore::FOpenMode::Write:
3042 return sim::SVFOpenMode::Write;
3043 case moore::FOpenMode::Append:
3044 return sim::SVFOpenMode::Append;
3045 case moore::FOpenMode::ReadUpdate:
3046 return sim::SVFOpenMode::ReadUpdate;
3047 case moore::FOpenMode::WriteUpdate:
3048 return sim::SVFOpenMode::WriteUpdate;
3049 case moore::FOpenMode::AppendUpdate:
3050 return sim::SVFOpenMode::AppendUpdate;
3052 llvm_unreachable(
"unknown FOpenMode");
3054 simMode = sim::SVFOpenModeAttr::get(op.getContext(),
3055 mapMode(modeAttr.getValue()));
3057 rewriter.replaceOpWithNewOp<sim::SVFOpenOp>(op, adaptor.getFilename(),
3063struct PlusArgsTestBIOpConversion
3065 using OpConversionPattern::OpConversionPattern;
3067 matchAndRewrite(PlusArgsTestBIOp op, OpAdaptor adaptor,
3068 ConversionPatternRewriter &rewriter)
const override {
3069 rewriter.replaceOpWithNewOp<sim::PlusArgsTestOp>(op, rewriter.getI1Type(),
3070 op.getFormatStringAttr());
3075struct PlusArgsValueBIOpConversion
3077 using OpConversionPattern::OpConversionPattern;
3079 matchAndRewrite(PlusArgsValueBIOp op, OpAdaptor adaptor,
3080 ConversionPatternRewriter &rewriter)
const override {
3081 auto resultType = typeConverter->convertType(op.getResult().getType());
3083 return rewriter.notifyMatchFailure(op,
"unsupported result type");
3084 rewriter.replaceOpWithNewOp<sim::PlusArgsValueOp>(
3085 op, rewriter.getI1Type(), resultType, op.getFormatStringAttr());
3091 using OpConversionPattern::OpConversionPattern;
3094 matchAndRewrite(FCloseBIOp op, OpAdaptor adaptor,
3095 ConversionPatternRewriter &rewriter)
const override {
3096 rewriter.replaceOpWithNewOp<sim::SVFCloseOp>(op, adaptor.getFd());
3102 using OpConversionPattern::OpConversionPattern;
3105 matchAndRewrite(FFlushBIOp op, OpAdaptor adaptor,
3106 ConversionPatternRewriter &rewriter)
const override {
3107 if (!adaptor.getFd()) {
3108 rewriter.replaceOpWithNewOp<sim::SVFFlushAllOp>(op);
3110 auto stream = sim::SVChannelToOutputStreamOp::create(
3111 rewriter, op.getLoc(), adaptor.getFd());
3112 rewriter.replaceOpWithNewOp<sim::FlushOp>(op, stream);
3119 using OpConversionPattern::OpConversionPattern;
3122 matchAndRewrite(StringCmpOp op, OpAdaptor adaptor,
3123 ConversionPatternRewriter &rewriter)
const override {
3124 sim::StringCmpPredicate pred;
3125 switch (op.getPredicate()) {
3126 case moore::StringCmpPredicate::eq:
3127 pred = sim::StringCmpPredicate::eq;
3129 case moore::StringCmpPredicate::ne:
3130 pred = sim::StringCmpPredicate::ne;
3132 case moore::StringCmpPredicate::lt:
3133 pred = sim::StringCmpPredicate::lt;
3135 case moore::StringCmpPredicate::le:
3136 pred = sim::StringCmpPredicate::le;
3138 case moore::StringCmpPredicate::gt:
3139 pred = sim::StringCmpPredicate::gt;
3141 case moore::StringCmpPredicate::ge:
3142 pred = sim::StringCmpPredicate::ge;
3145 rewriter.replaceOpWithNewOp<sim::StringCmpOp>(op, pred, adaptor.getLhs(),
3158static LogicalResult
convert(StopBIOp op, StopBIOp::Adaptor adaptor,
3159 ConversionPatternRewriter &rewriter) {
3160 rewriter.replaceOpWithNewOp<sim::PauseOp>(op,
false);
3165static LogicalResult
convert(FinishBIOp op, FinishBIOp::Adaptor adaptor,
3166 ConversionPatternRewriter &rewriter) {
3167 rewriter.replaceOpWithNewOp<sim::TerminateOp>(op, op.getExitCode() == 0,
3173static LogicalResult
convert(SeverityBIOp op, SeverityBIOp::Adaptor adaptor,
3174 ConversionPatternRewriter &rewriter) {
3176 std::string severityString;
3178 switch (op.getSeverity()) {
3179 case (Severity::Fatal):
3180 severityString =
"Fatal: ";
3182 case (Severity::Error):
3183 severityString =
"Error: ";
3185 case (Severity::Warning):
3186 severityString =
"Warning: ";
3188 case (Severity::Info):
3189 severityString =
"Info: ";
3194 sim::FormatLiteralOp::create(rewriter, op.getLoc(), severityString);
3195 auto message = sim::FormatStringConcatOp::create(
3196 rewriter, op.getLoc(), ValueRange{prefix, adaptor.getMessage()});
3197 rewriter.replaceOpWithNewOp<sim::PrintFormattedProcOp>(op, message);
3211 UrandomRangeBIOp::Adaptor adaptor,
3212 ConversionPatternRewriter &rewriter,
3213 FunctionCache &funcCache) {
3214 auto loc = op.getLoc();
3215 auto i32Ty = rewriter.getI32Type();
3216 auto ptrTy = LLVM::LLVMPointerType::get(rewriter.getContext());
3217 auto fn = funcCache.getOrCreate(rewriter,
"__circt_urandom_range",
3218 {i32Ty, i32Ty, ptrTy}, {i32Ty});
3221 if (
auto seedRef = adaptor.getSeed()) {
3224 seedPtr = LLVM::AllocaOp::create(rewriter, loc, ptrTy, i32Ty, one);
3225 auto seedVal = llhd::ProbeOp::create(rewriter, loc, seedRef);
3226 LLVM::StoreOp::create(rewriter, loc, seedVal, seedPtr);
3228 seedPtr = LLVM::ZeroOp::create(rewriter, loc, ptrTy);
3231 auto call = func::CallOp::create(
3233 ValueRange{adaptor.getMinval(), adaptor.getMaxval(), seedPtr});
3236 if (adaptor.getSeed()) {
3237 auto newSeed = LLVM::LoadOp::create(rewriter, loc, i32Ty, seedPtr);
3238 auto epsilon = llhd::ConstantTimeOp::create(
3240 llhd::TimeAttr::get(rewriter.getContext(), 0,
"ns", 0, 1));
3241 llhd::DriveOp::create(rewriter, loc, adaptor.getSeed(), newSeed, epsilon,
3245 rewriter.replaceOp(op, call.getResult(0));
3251 FinishMessageBIOp::Adaptor adaptor,
3252 ConversionPatternRewriter &rewriter) {
3254 rewriter.eraseOp(op);
3263static LogicalResult
convert(TimeBIOp op, TimeBIOp::Adaptor adaptor,
3264 ConversionPatternRewriter &rewriter) {
3265 rewriter.replaceOpWithNewOp<llhd::CurrentTimeOp>(op);
3270static LogicalResult
convert(LogicToTimeOp op, LogicToTimeOp::Adaptor adaptor,
3271 ConversionPatternRewriter &rewriter) {
3272 rewriter.replaceOpWithNewOp<llhd::IntToTimeOp>(op, adaptor.getInput());
3277static LogicalResult
convert(TimeToLogicOp op, TimeToLogicOp::Adaptor adaptor,
3278 ConversionPatternRewriter &rewriter) {
3279 rewriter.replaceOpWithNewOp<llhd::TimeToIntOp>(op, adaptor.getInput());
3288 const TypeConverter &converter) {
3289 target.addIllegalDialect<MooreDialect>();
3290 target.addLegalDialect<comb::CombDialect>();
3291 target.addLegalDialect<hw::HWDialect>();
3292 target.addLegalDialect<seq::SeqDialect>();
3293 target.addLegalDialect<llhd::LLHDDialect>();
3294 target.addLegalDialect<ltl::LTLDialect>();
3295 target.addLegalDialect<mlir::BuiltinDialect>();
3296 target.addLegalDialect<mlir::math::MathDialect>();
3297 target.addLegalDialect<sim::SimDialect>();
3298 target.addLegalDialect<mlir::LLVM::LLVMDialect>();
3299 target.addLegalDialect<verif::VerifDialect>();
3300 target.addLegalDialect<arith::ArithDialect>();
3302 target.addLegalOp<debug::ScopeOp>();
3304 target.addDynamicallyLegalOp<scf::YieldOp, func::CallOp, func::ReturnOp,
3305 UnrealizedConversionCastOp, hw::OutputOp,
3306 hw::InstanceOp, debug::ArrayOp, debug::StructOp,
3307 debug::VariableOp, arith::SelectOp>(
3308 [&](Operation *op) {
return converter.isLegal(op); });
3310 target.addDynamicallyLegalOp<scf::IfOp, scf::ForOp, scf::ExecuteRegionOp,
3311 scf::WhileOp, scf::ForallOp>([&](Operation *op) {
3312 return converter.isLegal(op) && !op->getParentOfType<llhd::ProcessOp>();
3315 target.addDynamicallyLegalOp<func::FuncOp>([&](func::FuncOp op) {
3316 return converter.isSignatureLegal(op.getFunctionType());
3320 return converter.isSignatureLegal(op.getModuleType().getFuncType()) &&
3321 converter.isLegal(&op.getBody());
3326 typeConverter.addConversion([&](IntType type) {
3327 return IntegerType::get(type.getContext(), type.getWidth());
3330 typeConverter.addConversion([&](RealType type) -> mlir::Type {
3331 MLIRContext *ctx = type.getContext();
3332 switch (type.getWidth()) {
3333 case moore::RealWidth::f32:
3334 return mlir::Float32Type::get(ctx);
3335 case moore::RealWidth::f64:
3336 return mlir::Float64Type::get(ctx);
3340 typeConverter.addConversion(
3341 [&](TimeType type) {
return llhd::TimeType::get(type.getContext()); });
3343 typeConverter.addConversion([&](FormatStringType type) {
3344 return sim::FormatStringType::get(type.getContext());
3347 typeConverter.addConversion([&](StringType type) {
3348 return sim::DynamicStringType::get(type.getContext());
3351 typeConverter.addConversion([&](QueueType type) {
3352 return sim::QueueType::get(type.getContext(),
3353 typeConverter.convertType(type.getElementType()),
3357 typeConverter.addConversion([&](ArrayType type) -> std::optional<Type> {
3358 if (
auto elementType = typeConverter.convertType(type.getElementType()))
3359 return hw::ArrayType::get(
elementType, type.getSize());
3366 typeConverter.addConversion(
3367 [&](UnpackedArrayType type) -> std::optional<Type> {
3368 if (
auto elementType = typeConverter.convertType(type.getElementType()))
3369 return hw::ArrayType::get(
elementType, type.getSize());
3373 typeConverter.addConversion([&](OpenArrayType type) -> std::optional<Type> {
3374 return LLVM::LLVMPointerType::get(type.getContext());
3377 typeConverter.addConversion(
3378 [&](OpenUnpackedArrayType type) -> std::optional<Type> {
3379 return LLVM::LLVMPointerType::get(type.getContext());
3382 typeConverter.addConversion([&](StructType type) -> std::optional<Type> {
3383 SmallVector<hw::StructType::FieldInfo> fields;
3384 for (
auto field : type.getMembers()) {
3385 hw::StructType::FieldInfo info;
3386 info.type = typeConverter.convertType(field.type);
3389 info.name = field.name;
3390 fields.push_back(info);
3392 return hw::StructType::get(type.getContext(), fields);
3400 typeConverter.addConversion(
3401 [&](UnpackedStructType type) -> std::optional<Type> {
3402 SmallVector<hw::StructType::FieldInfo> fields;
3403 for (
auto field : type.getMembers()) {
3404 hw::StructType::FieldInfo info;
3405 info.type = typeConverter.convertType(field.type);
3408 info.name = field.name;
3409 fields.push_back(info);
3411 return hw::StructType::get(type.getContext(), fields);
3415 typeConverter.addConversion([&](UnionType type) -> std::optional<Type> {
3416 SmallVector<hw::UnionType::FieldInfo> fields;
3417 for (
auto field : type.getMembers()) {
3418 hw::UnionType::FieldInfo info;
3419 info.type = typeConverter.convertType(field.type);
3422 info.name = field.name;
3424 fields.push_back(info);
3426 auto result = hw::UnionType::get(type.getContext(), fields);
3431 typeConverter.addConversion(
3432 [&](UnpackedUnionType type) -> std::optional<Type> {
3433 SmallVector<hw::UnionType::FieldInfo> fields;
3434 for (
auto field : type.getMembers()) {
3435 hw::UnionType::FieldInfo info;
3436 info.type = typeConverter.convertType(field.type);
3439 info.name = field.name;
3441 fields.push_back(info);
3443 return hw::UnionType::get(type.getContext(), fields);
3447 typeConverter.addConversion([&](ChandleType type) -> std::optional<Type> {
3448 return LLVM::LLVMPointerType::get(type.getContext());
3452 typeConverter.addConversion(
3453 [](LLVM::LLVMPointerType t) -> std::optional<Type> {
return t; });
3456 typeConverter.addConversion([&](ClassHandleType type) -> std::optional<Type> {
3457 return LLVM::LLVMPointerType::get(type.getContext());
3460 typeConverter.addConversion([&](RefType type) -> std::optional<Type> {
3461 if (isa<OpenArrayType, OpenUnpackedArrayType>(type.getNestedType()))
3462 return LLVM::LLVMPointerType::get(type.getContext());
3463 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
3464 return llhd::RefType::get(innerType);
3469 typeConverter.addConversion([](IntegerType type) {
return type; });
3470 typeConverter.addConversion([](FloatType type) {
return type; });
3471 typeConverter.addConversion([](sim::DynamicStringType type) {
return type; });
3472 typeConverter.addConversion([](sim::FormatStringType type) {
return type; });
3473 typeConverter.addConversion([](llhd::TimeType type) {
return type; });
3474 typeConverter.addConversion([](debug::ArrayType type) {
return type; });
3475 typeConverter.addConversion([](debug::ScopeType type) {
return type; });
3476 typeConverter.addConversion([](debug::StructType type) {
return type; });
3478 typeConverter.addConversion([&](llhd::RefType type) -> std::optional<Type> {
3479 if (
auto innerType = typeConverter.convertType(type.getNestedType()))
3480 return llhd::RefType::get(innerType);
3484 typeConverter.addConversion([&](hw::ArrayType type) -> std::optional<Type> {
3485 if (
auto elementType = typeConverter.convertType(type.getElementType()))
3486 return hw::ArrayType::get(
elementType, type.getNumElements());
3490 typeConverter.addConversion([&](hw::StructType type) -> std::optional<Type> {
3491 SmallVector<hw::StructType::FieldInfo> fields;
3492 for (
auto field : type.getElements()) {
3493 hw::StructType::FieldInfo info;
3494 info.type = typeConverter.convertType(field.type);
3497 info.name = field.name;
3498 fields.push_back(info);
3500 return hw::StructType::get(type.getContext(), fields);
3503 typeConverter.addConversion([&](hw::UnionType type) -> std::optional<Type> {
3504 SmallVector<hw::UnionType::FieldInfo> fields;
3505 for (
auto field : type.getElements()) {
3506 hw::UnionType::FieldInfo info;
3507 info.type = typeConverter.convertType(field.type);
3510 info.name = field.name;
3511 info.offset = field.offset;
3512 fields.push_back(info);
3514 return hw::UnionType::get(type.getContext(), fields);
3517 typeConverter.addTargetMaterialization(
3518 [&](mlir::OpBuilder &builder, mlir::Type resultType,
3519 mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
3520 if (inputs.size() != 1 || !inputs[0])
3522 return UnrealizedConversionCastOp::create(builder, loc, resultType,
3527 typeConverter.addSourceMaterialization(
3528 [&](mlir::OpBuilder &builder, mlir::Type resultType,
3529 mlir::ValueRange inputs, mlir::Location loc) -> mlir::Value {
3530 if (inputs.size() != 1)
3532 return UnrealizedConversionCastOp::create(builder, loc, resultType,
3539 TypeConverter &typeConverter,
3540 ClassTypeCache &classCache,
3541 FunctionCache &funcCache) {
3546 classCache, funcCache);
3547 patterns.add<ClassPropertyRefOpConversion>(typeConverter,
3548 patterns.getContext(), classCache);
3552 ClassUpcastOpConversion,
3554 VariableOpConversion,
3558 ConversionOpConversion,
3559 BitcastConversion<PackedToSBVOp>,
3560 BitcastConversion<SBVToPackedOp>,
3561 NoOpConversion<LogicToIntOp>,
3562 NoOpConversion<IntToLogicOp>,
3563 NoOpConversion<ToBuiltinIntOp>,
3564 NoOpConversion<FromBuiltinIntOp>,
3568 SIntToRealOpConversion,
3569 UIntToRealOpConversion,
3570 IntToStringOpConversion,
3571 FormatStringToStringOpConversion,
3572 RealToIntOpConversion,
3573 ConvertRealOpConversion,
3579 ReplicateOpConversion,
3581 ExtractOpConversion,
3582 DynExtractOpConversion,
3583 DynExtractRefOpConversion,
3585 StructExtractOpConversion,
3586 StructExtractRefOpConversion,
3587 ExtractRefOpConversion,
3588 StructCreateOpConversion,
3589 UnionCreateOpConversion,
3590 UnionExtractOpConversion,
3591 UnionExtractRefOpConversion,
3592 ConditionalOpConversion,
3593 ArrayCreateOpConversion,
3596 ConstantStringOpConv,
3599 ReduceAndOpConversion,
3600 ReduceOrOpConversion,
3601 ReduceXorOpConversion,
3602 BoolCastOpConversion,
3607 BinaryOpConversion<AddOp, comb::AddOp>,
3608 BinaryOpConversion<SubOp, comb::SubOp>,
3609 BinaryOpConversion<MulOp, comb::MulOp>,
3610 BinaryOpConversion<DivUOp, comb::DivUOp>,
3611 BinaryOpConversion<DivSOp, comb::DivSOp>,
3612 BinaryOpConversion<ModUOp, comb::ModUOp>,
3613 BinaryOpConversion<ModSOp, comb::ModSOp>,
3614 BinaryOpConversion<AndOp, comb::AndOp>,
3615 BinaryOpConversion<OrOp, comb::OrOp>,
3616 BinaryOpConversion<XorOp, comb::XorOp>,
3619 NegRealOpConversion,
3622 BinaryRealOpConversion<AddRealOp, arith::AddFOp>,
3623 BinaryRealOpConversion<SubRealOp, arith::SubFOp>,
3624 BinaryRealOpConversion<DivRealOp, arith::DivFOp>,
3625 BinaryRealOpConversion<MulRealOp, arith::MulFOp>,
3626 BinaryRealOpConversion<PowRealOp, math::PowFOp>,
3629 PowUOpConversion, PowSOpConversion,
3632 ICmpOpConversion<UltOp, ICmpPredicate::ult>,
3633 ICmpOpConversion<SltOp, ICmpPredicate::slt>,
3634 ICmpOpConversion<UleOp, ICmpPredicate::ule>,
3635 ICmpOpConversion<SleOp, ICmpPredicate::sle>,
3636 ICmpOpConversion<UgtOp, ICmpPredicate::ugt>,
3637 ICmpOpConversion<SgtOp, ICmpPredicate::sgt>,
3638 ICmpOpConversion<UgeOp, ICmpPredicate::uge>,
3639 ICmpOpConversion<SgeOp, ICmpPredicate::sge>,
3640 ICmpOpConversion<EqOp, ICmpPredicate::eq>,
3641 ICmpOpConversion<NeOp, ICmpPredicate::ne>,
3642 ICmpOpConversion<CaseEqOp, ICmpPredicate::ceq>,
3643 ICmpOpConversion<CaseNeOp, ICmpPredicate::cne>,
3644 ICmpOpConversion<WildcardEqOp, ICmpPredicate::weq>,
3645 ICmpOpConversion<WildcardNeOp, ICmpPredicate::wne>,
3646 FCmpOpConversion<NeRealOp, arith::CmpFPredicate::UNE>,
3647 FCmpOpConversion<FltOp, arith::CmpFPredicate::OLT>,
3648 FCmpOpConversion<FleOp, arith::CmpFPredicate::OLE>,
3649 FCmpOpConversion<FgtOp, arith::CmpFPredicate::OGT>,
3650 FCmpOpConversion<FgeOp, arith::CmpFPredicate::OGE>,
3651 FCmpOpConversion<EqRealOp, arith::CmpFPredicate::OEQ>,
3652 CaseXZEqOpConversion<CaseZEqOp, true>,
3653 CaseXZEqOpConversion<CaseXZEqOp, false>,
3656 SVModuleOpConversion,
3657 InstanceOpConversion,
3658 ProcedureOpConversion,
3659 CoroutineOpConversion,
3660 CallCoroutineOpConversion,
3661 WaitEventOpConversion,
3669 AssignOpConversion<ContinuousAssignOp>,
3670 AssignOpConversion<DelayedContinuousAssignOp>,
3671 AssignOpConversion<BlockingAssignOp>,
3672 AssignOpConversion<NonBlockingAssignOp>,
3673 AssignOpConversion<DelayedNonBlockingAssignOp>,
3674 AssignedVariableOpConversion,
3677 HWInstanceOpConversion,
3680 DPIFuncOpConversion,
3681 FuncDPICallOpConversion,
3682 UnrealizedConversionCastConversion,
3683 InPlaceOpConversion<debug::ArrayOp>,
3684 InPlaceOpConversion<debug::StructOp>,
3685 InPlaceOpConversion<debug::VariableOp>,
3688 AssertLikeOpConversion<AssertOp, verif::AssertOp>,
3689 AssertLikeOpConversion<AssumeOp, verif::AssumeOp>,
3690 AssertLikeOpConversion<CoverOp, verif::CoverOp>,
3693 FormatLiteralOpConversion,
3694 FormatStringOpConversion,
3695 FormatConcatOpConversion,
3696 FormatHierPathOpConversion,
3697 FormatIntOpConversion,
3698 FormatRealOpConversion,
3699 FormatCharOpConversion,
3700 DisplayBIOpConversion,
3701 FDisplayBIOpConversion,
3704 FOpenBIOpConversion,
3705 FCloseBIOpConversion,
3706 FFlushBIOpConversion,
3709 PlusArgsTestBIOpConversion,
3710 PlusArgsValueBIOpConversion,
3713 StringLenOpConversion,
3714 StringConcatOpConversion,
3715 StringGetOpConversion,
3716 StringCmpOpConversion,
3719 QueueSizeBIOpConversion,
3720 QueuePushBackOpConversion,
3721 QueuePushFrontOpConversion,
3722 QueuePopBackOpConversion,
3723 QueuePopFrontOpConversion,
3724 QueueDeleteOpConversion,
3725 QueueInsertOpConversion,
3726 QueueClearOpConversion,
3727 DynQueueExtractOpConversion,
3728 QueueResizeOpConversion,
3729 QueueSetOpConversion,
3730 QueueCmpOpConversion,
3731 QueueFromUnpackedArrayOpConversion,
3732 QueueConcatOpConversion
3733 >(typeConverter,
patterns.getContext());
3756 mlir::populateAnyFunctionOpInterfaceTypeConversionPattern(
patterns,
3758 hw::populateHWModuleLikeTypeConversionPattern(
3759 hw::HWModuleOp::getOperationName(),
patterns, typeConverter);
3760 populateSCFToControlFlowConversionPatterns(
patterns);
3769struct MooreToCorePass
3770 :
public circt::impl::ConvertMooreToCoreBase<MooreToCorePass> {
3771 void runOnOperation()
override;
3777 return std::make_unique<MooreToCorePass>();
3781void MooreToCorePass::runOnOperation() {
3782 MLIRContext &
context = getContext();
3783 ModuleOp
module = getOperation();
3784 ClassTypeCache classCache;
3785 auto &symbolTable = getAnalysis<SymbolTable>();
3786 FunctionCache funcCache(symbolTable);
3788 IRRewriter rewriter(module);
3789 (void)mlir::eraseUnreachableBlocks(rewriter, module->getRegions());
3791 TypeConverter typeConverter;
3794 ConversionTarget target(
context);
3799 mlir::cf::populateCFStructuralTypeConversionsAndLegality(typeConverter,
3802 if (failed(applyFullConversion(module, target, std::move(
patterns))))
3803 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.