14 #include "../PassDetail.h"
22 #include "mlir/Conversion/ArithToLLVM/ArithToLLVM.h"
23 #include "mlir/Conversion/ControlFlowToLLVM/ControlFlowToLLVM.h"
24 #include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVM.h"
25 #include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVMPass.h"
26 #include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
27 #include "mlir/Conversion/LLVMCommon/Pattern.h"
28 #include "mlir/Conversion/ReconcileUnrealizedCasts/ReconcileUnrealizedCasts.h"
29 #include "mlir/Dialect/Arith/IR/Arith.h"
30 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
31 #include "mlir/IR/IRMapping.h"
32 #include "mlir/Pass/Pass.h"
33 #include "mlir/Transforms/DialectConversion.h"
36 using namespace circt;
45 const TypeConverter *typeConverter,
46 LLVM::GlobalOp &str) {
50 auto addr =
builder.create<LLVM::AddressOfOp>(loc, voidPtrTy, str.getName());
51 auto idx =
builder.create<LLVM::ConstantOp>(loc, i32Ty,
53 std::array<Value, 2> idxs({idx, idx});
54 return builder.create<LLVM::GEPOp>(loc, voidPtrTy, str.getType(), addr, idxs);
61 static LLVM::LLVMFuncOp
63 Location loc, std::string name, Type signature,
64 bool insertBodyAndTerminator =
false) {
65 auto func = module.lookupSymbol<LLVM::LLVMFuncOp>(name);
67 OpBuilder moduleBuilder(module.getBodyRegion());
68 func = moduleBuilder.create<LLVM::LLVMFuncOp>(loc, name, signature);
69 if (insertBodyAndTerminator) {
70 func.addEntryBlock(moduleBuilder);
71 OpBuilder b(func.getBody());
72 b.create<LLVM::ReturnOp>(loc, ValueRange());
83 return LLVM::LLVMStructType::getLiteral(dialect->getContext(),
84 {voidPtrTy, i64Ty, i64Ty, i64Ty});
90 LLVM::LLVMDialect *dialect,
91 Location loc, Value signal,
92 bool extractIndices =
false) {
98 std::vector<Value> result;
101 auto sigPtrPtr = rewriter.create<LLVM::GEPOp>(loc, voidPtrTy, sigTy, signal,
102 ArrayRef<LLVM::GEPArg>({0, 0}));
103 result.push_back(rewriter.create<LLVM::LoadOp>(loc, voidPtrTy, sigPtrPtr));
105 auto offsetPtr = rewriter.create<LLVM::GEPOp>(loc, voidPtrTy, sigTy, signal,
106 ArrayRef<LLVM::GEPArg>({0, 1}));
107 result.push_back(rewriter.create<LLVM::LoadOp>(loc, i64Ty, offsetPtr));
110 if (extractIndices) {
111 auto instIndexPtr = rewriter.create<LLVM::GEPOp>(
112 loc, voidPtrTy, sigTy, signal, ArrayRef<LLVM::GEPArg>({0, 2}));
113 result.push_back(rewriter.create<LLVM::LoadOp>(loc, i64Ty, instIndexPtr));
115 auto globalIndexPtr = rewriter.create<LLVM::GEPOp>(
116 loc, voidPtrTy, sigTy, signal, ArrayRef<LLVM::GEPArg>({0, 3}));
117 result.push_back(rewriter.create<LLVM::LoadOp>(loc, i64Ty, globalIndexPtr));
125 ConversionPatternRewriter &rewriter, Location loc,
126 std::vector<Value> originDetail, Value newPtr,
132 auto sigUndef = rewriter.create<LLVM::UndefOp>(loc, sigTy);
134 rewriter.create<LLVM::InsertValueOp>(loc, sigUndef, newPtr, 0);
135 auto storeSubOffset =
136 rewriter.create<LLVM::InsertValueOp>(loc, storeSubPtr, newOffset, 1);
137 auto storeSubInstIndex = rewriter.create<LLVM::InsertValueOp>(
138 loc, storeSubOffset, originDetail[2], 2);
139 auto storeSubGlobalIndex = rewriter.create<LLVM::InsertValueOp>(
140 loc, storeSubInstIndex, originDetail[3], 3);
143 auto oneC = rewriter.create<LLVM::ConstantOp>(loc, i32Ty,
144 rewriter.getI32IntegerAttr(1));
145 auto allocaSubSig = rewriter.create<LLVM::AllocaOp>(
147 rewriter.create<LLVM::StoreOp>(loc, storeSubGlobalIndex, allocaSubSig);
155 for (
auto arg : op.getDestOps()) {
165 for (
auto user : op->getUsers()) {
166 if (
auto wait = dyn_cast<WaitOp>(user))
176 const TypeConverter *converter, ProcOp &proc) {
177 SmallVector<Type, 3> types = SmallVector<Type, 3>();
178 proc.walk([&](Operation *op) ->
void {
179 if (op->isUsedOutsideOfBlock(op->getBlock()) ||
isWaitDestArg(op)) {
180 auto ty = op->getResult(0).getType();
181 auto convertedTy = converter->convertType(ty);
182 types.push_back(convertedTy);
187 for (
auto &block : proc.getBlocks()) {
189 if (block.isEntryBlock())
192 for (
auto arg : block.getArguments()) {
193 if (arg.isUsedOutsideOfBlock(&block)) {
194 types.push_back(converter->convertType(arg.getType()));
199 return LLVM::LLVMStructType::getLiteral(dialect->getContext(), types);
206 LLVM::LLVMDialect *dialect, Location loc,
207 Region *body, Value resumeIdx,
int currIdx,
208 Block *trueDest, ValueRange trueDestArgs,
209 Block *falseDest =
nullptr) {
211 auto secondBlock = ++body->begin();
212 auto newBlock = rewriter.createBlock(body, secondBlock);
213 auto cmpIdx = rewriter.create<LLVM::ConstantOp>(
214 loc, i32Ty, rewriter.getI32IntegerAttr(currIdx));
215 auto cmpRes = rewriter.create<LLVM::ICmpOp>(loc, LLVM::ICmpPredicate::eq,
221 falseDest = &*secondBlock;
223 rewriter.create<LLVM::CondBrOp>(loc, cmpRes, trueDest, trueDestArgs,
224 falseDest, ValueRange());
227 auto entryTer = body->front().getTerminator();
228 entryTer->setSuccessor(newBlock, 0);
234 ConversionPatternRewriter &rewriter,
235 Type stateTy,
int index, Value state) {
236 return rewriter.create<LLVM::GEPOp>(
238 ArrayRef<LLVM::GEPArg>({0, 3, index}));
245 const TypeConverter *converter,
246 ConversionPatternRewriter &rewriter, Type stateTy,
247 int &i, Value state, Value persist) {
248 auto elemTy = stateTy.cast<LLVM::LLVMStructType>()
250 .cast<LLVM::LLVMStructType>()
253 if (
auto arg = persist.dyn_cast<BlockArgument>()) {
254 rewriter.setInsertionPointToStart(arg.getParentBlock());
256 rewriter.setInsertionPointAfter(persist.getDefiningOp());
259 Value convPersist = converter->materializeTargetConversion(
260 rewriter, loc, converter->convertType(persist.getType()), {persist});
265 if (
auto ptr = persist.getType().dyn_cast<PtrType>()) {
267 auto elemTy = converter->convertType(ptr.getUnderlyingType());
268 toStore = rewriter.create<LLVM::LoadOp>(loc, elemTy, convPersist);
269 }
else if (persist.getType().isa<SigType>()) {
271 toStore = rewriter.create<LLVM::LoadOp>(loc,
getLLVMSigType(dialect),
275 toStore = convPersist;
278 rewriter.create<LLVM::StoreOp>(loc, toStore, gep0);
282 for (
auto &use : llvm::make_early_inc_range(persist.getUses())) {
283 auto user = use.getOwner();
284 if (persist.getType().isa<PtrType>() && user != toStore.getDefiningOp() &&
285 user != convPersist.getDefiningOp() &&
286 persist.getParentBlock() == user->getBlock()) {
291 }
else if (persist.getParentBlock() != user->getBlock() ||
292 (isa<WaitOp>(user) &&
297 if (isa<WaitOp>(user) &&
isWaitDestArg(cast<WaitOp>(user), persist))
298 rewriter.setInsertionPoint(
299 user->getParentRegion()->front().getTerminator());
301 rewriter.setInsertionPointToStart(user->getBlock());
307 if (persist.getType().isa<PtrType, SigType>()) {
310 auto load1 = rewriter.create<LLVM::LoadOp>(loc, elemTy, gep1);
322 ConversionPatternRewriter &rewriter,
323 LLVM::LLVMDialect *dialect, Location loc,
324 ProcOp &proc, Type &stateTy,
325 LLVM::LLVMFuncOp &converted,
326 Operation *splitEntryBefore) {
329 auto &firstBB = converted.getBody().front();
334 rewriter.splitBlock(&firstBB, splitEntryBefore->getIterator());
338 rewriter.setInsertionPointToEnd(&firstBB);
339 rewriter.create<LLVM::BrOp>(loc, ValueRange(), splitFirst);
342 rewriter.setInsertionPoint(firstBB.getTerminator());
343 auto gep = rewriter.create<LLVM::GEPOp>(
345 converted.getArgument(1), ArrayRef<LLVM::GEPArg>({1}));
347 auto larg = rewriter.create<LLVM::LoadOp>(loc, i32Ty, gep);
349 auto body = &converted.getBody();
352 auto abortBlock = rewriter.createBlock(body, body->end());
353 rewriter.create<LLVM::ReturnOp>(loc, ValueRange());
359 ValueRange(), abortBlock);
368 converted.walk([&](Operation *op) ->
void {
369 if ((op->isUsedOutsideOfBlock(op->getBlock()) ||
isWaitDestArg(op)) &&
370 op->getResult(0) != larg.getResult()) {
371 persistValue(dialect, loc, converter, rewriter, stateTy, i,
372 converted.getArgument(1), op->getResult(0));
376 if (
auto wait = dyn_cast<WaitOp>(op)) {
378 wait.getDest(), wait.getDestOps());
381 rewriter.setInsertionPoint(op);
382 auto procState = op->getParentOfType<LLVM::LLVMFuncOp>().getArgument(1);
383 auto resumeIdxC = rewriter.create<LLVM::ConstantOp>(
384 loc, i32Ty, rewriter.getI32IntegerAttr(waitInd));
385 auto resumeIdxPtr = rewriter.create<LLVM::GEPOp>(
387 procState, ArrayRef<LLVM::GEPArg>({1}));
388 rewriter.create<LLVM::StoreOp>(op->getLoc(), resumeIdxC, resumeIdxPtr);
393 for (
auto &block : converted.getBlocks()) {
395 if (block.isEntryBlock())
398 for (
auto arg : block.getArguments()) {
399 if (arg.isUsedOutsideOfBlock(&block)) {
400 persistValue(dialect, loc, converter, rewriter, stateTy, i,
401 converted.getArgument(1), arg);
412 SmallVector<Type, 4> types;
413 entity->walk([&](RegOp op) {
415 for (
size_t i = 0; i < op.getModes().size(); ++i) {
416 auto mode = op.getRegModeAt(i);
417 if (mode == RegMode::fall || mode == RegMode::rise ||
418 mode == RegMode::both)
425 return LLVM::LLVMStructType::getLiteral(dialect->getContext(), types);
431 static Value
zextByOne(Location loc, ConversionPatternRewriter &rewriter,
433 auto valueTy = value.getType();
435 valueTy.getIntOrFloatBitWidth() + 1);
436 return rewriter.create<LLVM::ZExtOp>(loc, zextTy, value);
441 Type targetTy, Value value) {
442 auto valueWidth = value.getType().getIntOrFloatBitWidth();
443 auto targetWidth = targetTy.getIntOrFloatBitWidth();
445 if (valueWidth < targetWidth)
446 return rewriter.create<LLVM::ZExtOp>(loc, targetTy, value);
448 if (valueWidth > targetWidth)
449 return rewriter.create<LLVM::TruncOp>(loc, targetTy, value);
455 for (
unsigned j = 0, e = op->getNumResults(); j < e; ++j) {
456 if (result == result.getDefiningOp()->getResult(j))
460 "no way to recurse to an operation that does not return any value");
469 SmallVector<Value> clonedOperands;
470 Operation *initOp = init.getDefiningOp();
475 if (!initOp || isa<llhd::PrbOp>(initOp))
478 for (
size_t i = 0, e = initOp->getNumOperands(); i < e; ++i) {
479 Value operand = initOp->getOperand(i);
484 if (
auto memorizedOperand = mapping.lookupOrNull(operand)) {
485 clonedOperands.push_back(memorizedOperand);
494 mapping.map(operand, clonedOperand);
495 clonedOperands.push_back(clonedOperand);
498 Operation *clone = initOp->clone();
499 clone->setOperands(clonedOperands);
504 return initBuilder.insert(clone)->getResult(index);
510 return type.isa<LLVM::LLVMArrayType, LLVM::LLVMStructType, hw::ArrayType,
516 static std::pair<Value, Value>
518 ConversionPatternRewriter &rewriter, Value pointer,
523 auto ptrToInt = rewriter.create<LLVM::PtrToIntOp>(loc, i64Ty, pointer);
524 auto const8 = rewriter.create<LLVM::ConstantOp>(
525 loc, index.getType(), rewriter.getI64IntegerAttr(8));
526 auto ptrOffset = rewriter.create<LLVM::UDivOp>(loc, index, const8);
527 auto shiftedPtr = rewriter.create<LLVM::AddOp>(loc, ptrToInt, ptrOffset);
528 auto newPtr = rewriter.create<LLVM::IntToPtrOp>(loc, voidPtrTy, shiftedPtr);
531 auto bitOffset = rewriter.create<LLVM::URemOp>(loc, index, const8);
533 return std::make_pair(newPtr, bitOffset);
539 ConversionPatternRewriter &rewriter,
540 Type elemTy, Value pointer,
541 LLVM::GEPArg index) {
544 return rewriter.create<LLVM::GEPOp>(loc, voidPtrTy, elemTy, pointer,
545 ArrayRef<LLVM::GEPArg>({0, index}));
551 ConversionPatternRewriter &rewriter,
552 Type arrTy, Value pointer,
553 LLVM::GEPArg index) {
554 if (
auto indexValue = dyn_cast<Value>(index))
555 index =
zextByOne(loc, rewriter, indexValue);
564 auto &context = converter.getContext();
591 struct EntityOpConversion :
public ConvertToLLVMPattern {
592 explicit EntityOpConversion(MLIRContext *ctx,
593 LLVMTypeConverter &typeConverter,
594 size_t &sigCounter,
size_t ®Counter)
595 : ConvertToLLVMPattern(llhd::EntityOp::getOperationName(), ctx,
597 sigCounter(sigCounter), regCounter(regCounter) {}
600 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
601 ConversionPatternRewriter &rewriter)
const override {
603 EntityOpAdaptor transformed(operands);
605 auto entityOp = cast<EntityOp>(op);
608 auto voidTy = getVoidType();
609 auto voidPtrTy = getVoidPtrType();
616 LLVMTypeConverter::SignatureConversion intermediate(
617 entityOp.getNumArguments());
619 intermediate.addInputs(
620 std::array<Type, 3>({voidPtrTy, voidPtrTy, voidPtrTy}));
621 for (
size_t i = 0, e = entityOp.getNumArguments(); i < e; ++i)
622 intermediate.addInputs(i, voidTy);
623 rewriter.applySignatureConversion(&entityOp.getBody(), intermediate,
626 OpBuilder bodyBuilder =
627 OpBuilder::atBlockBegin(&entityOp.getBlocks().front());
628 LLVMTypeConverter::SignatureConversion
final(
629 intermediate.getConvertedTypes().size());
630 final.addInputs(0, voidPtrTy);
631 final.addInputs(1, voidPtrTy);
632 final.addInputs(2, voidPtrTy);
636 sigCounter = entityOp.getNumArguments();
637 for (
size_t i = 0; i < sigCounter; ++i) {
639 auto gep = bodyBuilder.create<LLVM::GEPOp>(op->getLoc(), voidPtrTy, sigTy,
640 entityOp.getArgument(2),
643 final.remapInput(i + 3, gep.getResult());
646 rewriter.applySignatureConversion(&entityOp.getBody(),
final,
654 auto llvmFunc = rewriter.create<LLVM::LLVMFuncOp>(
655 op->getLoc(), entityOp.getName(), funcTy);
658 rewriter.setInsertionPointToEnd(&entityOp.getBlocks().front());
659 rewriter.create<LLVM::ReturnOp>(op->getLoc(), ValueRange{});
662 rewriter.inlineRegionBefore(entityOp.getBody(), llvmFunc.getBody(),
666 rewriter.eraseOp(op);
681 struct ProcOpConversion :
public ConvertToLLVMPattern {
682 explicit ProcOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter)
683 : ConvertToLLVMPattern(ProcOp::getOperationName(), ctx, typeConverter) {}
686 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
687 ConversionPatternRewriter &rewriter)
const override {
688 auto procOp = cast<ProcOp>(op);
691 ProcOpAdaptor transformed(operands);
694 auto voidTy = getVoidType();
695 auto voidPtrTy = getVoidPtrType();
697 auto stateTy = LLVM::LLVMStructType::getLiteral(
698 rewriter.getContext(),
702 getProcPersistenceTy(&getDialect(), typeConverter, procOp)});
707 auto &firstOp = op->getRegion(0).front().front();
711 LLVMTypeConverter::SignatureConversion intermediate(
712 procOp.getNumArguments());
714 std::array<Type, 3> procArgTys({voidPtrTy, voidPtrTy, voidPtrTy});
715 intermediate.addInputs(procArgTys);
716 for (
size_t i = 0, e = procOp.getNumArguments(); i < e; ++i)
717 intermediate.addInputs(i, voidTy);
718 rewriter.applySignatureConversion(&procOp.getBody(), intermediate,
722 OpBuilder bodyBuilder =
723 OpBuilder::atBlockBegin(&procOp.getBlocks().front());
724 LLVMTypeConverter::SignatureConversion
final(
725 intermediate.getConvertedTypes().size());
726 final.addInputs(0, voidPtrTy);
727 final.addInputs(1, voidPtrTy);
728 final.addInputs(2, voidPtrTy);
730 for (
size_t i = 0, e = procOp.getNumArguments(); i < e; ++i) {
732 auto gep = bodyBuilder.create<LLVM::GEPOp>(op->getLoc(), voidPtrTy, sigTy,
733 procOp.getArgument(2),
737 final.remapInput(i + 3, gep.getResult());
744 auto llvmFunc = rewriter.create<LLVM::LLVMFuncOp>(op->getLoc(),
745 procOp.getName(), funcTy);
746 llvmFunc->setAttr(
"llhd.argument_count",
747 rewriter.getI32IntegerAttr(procOp.getNumArguments()));
750 rewriter.inlineRegionBefore(procOp.getBody(), llvmFunc.getBody(),
754 procOp, stateTy, llvmFunc, &firstOp);
758 if (failed(rewriter.convertRegionTypes(&llvmFunc.getBody(), *typeConverter,
763 rewriter.eraseOp(op);
774 struct HaltOpConversion :
public ConvertToLLVMPattern {
775 explicit HaltOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter)
776 : ConvertToLLVMPattern(HaltOp::getOperationName(), ctx, typeConverter) {}
779 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
780 ConversionPatternRewriter &rewriter)
const override {
783 auto llvmFunc = op->getParentOfType<LLVM::LLVMFuncOp>();
784 auto procState = llvmFunc.getArgument(1);
788 rewriter.create<LLVM::GEPOp>(op->getLoc(), voidPtrTy, voidPtrTy,
789 procState, ArrayRef<LLVM::GEPArg>({2}));
791 rewriter.create<LLVM::LoadOp>(op->getLoc(), voidPtrTy, sensePtrGep);
794 unsigned numSenseEntries =
795 llvmFunc->getAttrOfType<IntegerAttr>(
"llhd.argument_count")
798 auto zeroB = rewriter.create<LLVM::ConstantOp>(op->getLoc(), i1Ty,
799 rewriter.getBoolAttr(
false));
800 for (
unsigned i = 0; i < numSenseEntries; ++i) {
801 auto senseElemPtr = rewriter.create<LLVM::GEPOp>(
802 op->getLoc(), voidPtrTy, i1Ty, sensePtr, ArrayRef<LLVM::GEPArg>({i}));
803 rewriter.create<LLVM::StoreOp>(op->getLoc(), zeroB, senseElemPtr);
806 rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, ValueRange());
816 struct WaitOpConversion :
public ConvertToLLVMPattern {
817 explicit WaitOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter)
818 : ConvertToLLVMPattern(WaitOp::getOperationName(), ctx, typeConverter) {}
821 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
822 ConversionPatternRewriter &rewriter)
const override {
823 auto waitOp = cast<WaitOp>(op);
824 WaitOpAdaptor transformed(operands, op->getAttrDictionary());
825 auto llvmFunc = op->getParentOfType<LLVM::LLVMFuncOp>();
827 auto voidTy = getVoidType();
828 auto voidPtrTy = getVoidPtrType();
834 voidTy, {voidPtrTy, voidPtrTy, i64Ty, i64Ty, i64Ty});
835 auto module = op->getParentOfType<ModuleOp>();
837 "llhdSuspend", llhdSuspendTy);
839 auto statePtr = llvmFunc.getArgument(0);
840 auto procState = llvmFunc.getArgument(1);
844 rewriter.create<LLVM::GEPOp>(op->getLoc(), voidPtrTy, voidPtrTy,
845 procState, ArrayRef<LLVM::GEPArg>({2}));
847 rewriter.create<LLVM::LoadOp>(op->getLoc(), voidPtrTy, sensePtrGep);
850 unsigned numSenseEntries =
851 llvmFunc->getAttrOfType<IntegerAttr>(
"llhd.argument_count")
854 if (waitOp.getObs().size() < numSenseEntries) {
855 auto zeroB = rewriter.create<LLVM::ConstantOp>(
856 op->getLoc(), i1Ty, rewriter.getBoolAttr(
false));
857 for (
size_t i = 0; i < numSenseEntries; ++i) {
859 rewriter.create<LLVM::GEPOp>(op->getLoc(), voidPtrTy, i1Ty,
860 sensePtr, ArrayRef<LLVM::GEPArg>({i}));
861 rewriter.create<LLVM::StoreOp>(op->getLoc(), zeroB, senseElemPtr);
866 for (
auto observed : transformed.getObs()) {
868 rewriter.create<LLVM::GEPOp>(op->getLoc(), voidPtrTy, i64Ty, observed,
869 ArrayRef<LLVM::GEPArg>({2}));
871 rewriter.create<LLVM::LoadOp>(op->getLoc(), i64Ty, instIndexPtr)
873 auto oneB = rewriter.create<LLVM::ConstantOp>(op->getLoc(), i1Ty,
874 rewriter.getBoolAttr(
true));
875 auto senseElementPtr =
876 rewriter.create<LLVM::GEPOp>(op->getLoc(), voidPtrTy, i1Ty, sensePtr,
877 ArrayRef<LLVM::GEPArg>({instIndex}));
878 rewriter.create<LLVM::StoreOp>(op->getLoc(), oneB, senseElementPtr);
883 if (waitOp.getTime()) {
884 auto realTime = rewriter.create<LLVM::ExtractValueOp>(
885 op->getLoc(), transformed.getTime(), 0);
886 auto delta = rewriter.create<LLVM::ExtractValueOp>(
887 op->getLoc(), transformed.getTime(), 1);
888 auto eps = rewriter.create<LLVM::ExtractValueOp>(
889 op->getLoc(), transformed.getTime(), 2);
891 std::array<Value, 5> args({statePtr, procState, realTime, delta, eps});
892 rewriter.create<LLVM::CallOp>(op->getLoc(), std::nullopt,
896 rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, ValueRange());
906 struct InstOpConversion :
public ConvertToLLVMPattern {
907 explicit InstOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter)
908 : ConvertToLLVMPattern(InstOp::getOperationName(), ctx, typeConverter) {}
911 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
912 ConversionPatternRewriter &rewriter)
const override {
914 auto instOp = cast<InstOp>(op);
916 auto module = op->getParentOfType<ModuleOp>();
917 auto entity = op->getParentOfType<EntityOp>();
919 auto voidTy = getVoidType();
920 auto voidPtrTy = getVoidPtrType();
935 "malloc", mallocSigFuncTy);
941 i32Ty, {voidPtrTy, i32Ty, voidPtrTy, voidPtrTy, i64Ty});
943 "allocSignal", allocSigFuncTy);
948 auto addSigArrElemFuncTy =
950 auto addSigElemFunc =
952 "addSigArrayElements", addSigArrElemFuncTy);
956 auto addSigStructElemFuncTy =
958 auto addSigStructFunc =
960 "addSigStructElement", addSigStructElemFuncTy);
963 auto allocProcFuncTy =
966 "allocProc", allocProcFuncTy);
969 auto allocEntityFuncTy =
972 module, rewriter, op->getLoc(),
"allocEntity", allocEntityFuncTy);
974 Value initStatePtr = initFunc.getArgument(0);
977 OpBuilder initBuilder =
978 OpBuilder::atBlockTerminator(&initFunc.getBody().getBlocks().front());
981 auto ownerName = entity.getName().str() +
"." + instOp.getName().str();
986 module.lookupSymbol<LLVM::GlobalOp>(
"instance." + ownerName);
988 owner = LLVM::createGlobalString(
989 op->getLoc(), initBuilder,
"instance." + ownerName, ownerName +
'\0',
990 LLVM::Linkage::Internal);
991 parentSym = module.lookupSymbol<LLVM::GlobalOp>(
"instance." + ownerName);
998 if (
auto child = module.lookupSymbol<EntityOp>(instOp.getCallee())) {
999 auto regStateTy =
getRegStateTy(&getDialect(), child.getOperation());
1002 auto regNull = initBuilder.create<LLVM::ZeroOp>(op->getLoc(), voidPtrTy);
1004 initBuilder.create<LLVM::GEPOp>(op->getLoc(), voidPtrTy, regStateTy,
1005 regNull, ArrayRef<LLVM::GEPArg>({1}));
1007 initBuilder.create<LLVM::PtrToIntOp>(op->getLoc(), i64Ty, regGep);
1010 auto regMall = initBuilder
1011 .create<LLVM::CallOp>(op->getLoc(), voidPtrTy,
1013 ArrayRef<Value>({regSize}))
1015 auto zeroB = initBuilder.create<LLVM::ConstantOp>(
1016 op->getLoc(), i1Ty, rewriter.getBoolAttr(
false));
1020 e = regStateTy.cast<LLVM::LLVMStructType>().getBody().size();
1022 size_t f = regStateTy.cast<LLVM::LLVMStructType>()
1024 .cast<LLVM::LLVMArrayType>()
1026 for (
size_t j = 0; j < f; ++j) {
1027 auto regGep = initBuilder.create<LLVM::GEPOp>(
1028 op->getLoc(), voidPtrTy, regStateTy, regMall,
1029 ArrayRef<LLVM::GEPArg>({0, i, j}));
1030 initBuilder.create<LLVM::StoreOp>(op->getLoc(), zeroB, regGep);
1035 initBuilder.create<LLVM::CallOp>(
1037 ArrayRef<Value>({initStatePtr, owner, regMall}));
1040 int initCounter = 0;
1042 WalkResult sigWalkResult = child.walk([&](SigOp op) -> WalkResult {
1044 auto underlyingTy = typeConverter->convertType(op.getInit().getType());
1046 auto indexConst = initBuilder.create<LLVM::ConstantOp>(
1047 op.getLoc(), i32Ty, rewriter.getI32IntegerAttr(initCounter));
1056 return WalkResult::interrupt();
1058 Value initDefCast = typeConverter->materializeTargetConversion(
1059 initBuilder, initDef.getLoc(),
1060 typeConverter->convertType(initDef.getType()), initDef);
1063 auto twoC = initBuilder.create<LLVM::ConstantOp>(
1064 op.getLoc(), i64Ty, rewriter.getI32IntegerAttr(2));
1065 auto nullPtr = initBuilder.create<LLVM::ZeroOp>(op.getLoc(), voidPtrTy);
1066 auto sizeGep = initBuilder.create<LLVM::GEPOp>(
1067 op.getLoc(), voidPtrTy, underlyingTy, nullPtr,
1068 ArrayRef<LLVM::GEPArg>({1}));
1070 initBuilder.create<LLVM::PtrToIntOp>(op.getLoc(), i64Ty, sizeGep);
1074 initBuilder.create<LLVM::MulOp>(op.getLoc(), i64Ty, size, twoC);
1075 std::array<Value, 1> margs({mallocSize});
1078 .create<LLVM::CallOp>(op.getLoc(), voidPtrTy,
1083 initBuilder.create<LLVM::StoreOp>(op.getLoc(), initDefCast, mall);
1088 if (
auto intTy = underlyingTy.dyn_cast<IntegerType>()) {
1089 auto byteWidth = llvm::divideCeil(intTy.getWidth(), 8);
1090 passSize = initBuilder.create<LLVM::ConstantOp>(
1091 op.getLoc(), i64Ty, rewriter.getI64IntegerAttr(byteWidth));
1096 std::array<Value, 5> args(
1097 {initStatePtr, indexConst, owner, mall, passSize});
1100 .create<LLVM::CallOp>(op.getLoc(), i32Ty,
1105 if (
auto arrayTy = underlyingTy.dyn_cast<LLVM::LLVMArrayType>()) {
1106 auto numElements = initBuilder.create<LLVM::ConstantOp>(
1108 rewriter.getI32IntegerAttr(arrayTy.getNumElements()));
1111 auto null = initBuilder.create<LLVM::ZeroOp>(op.getLoc(), voidPtrTy);
1112 auto gepFirst = initBuilder.create<LLVM::GEPOp>(
1113 op.getLoc(), voidPtrTy, arrayTy,
null,
1114 ArrayRef<LLVM::GEPArg>({0, 1}));
1115 auto toInt = initBuilder.create<LLVM::PtrToIntOp>(op.getLoc(), i32Ty,
1119 initBuilder.create<LLVM::CallOp>(
1121 ArrayRef<Value>({initStatePtr, sigIndex, toInt,
numElements}));
1122 }
else if (
auto structTy =
1123 underlyingTy.dyn_cast<LLVM::LLVMStructType>()) {
1124 auto null = initBuilder.create<LLVM::ZeroOp>(op.getLoc(), voidPtrTy);
1125 for (
size_t i = 0, e = structTy.getBody().size(); i < e; ++i) {
1127 auto gepElem = initBuilder.create<LLVM::GEPOp>(
1128 op.getLoc(), voidPtrTy, structTy,
null,
1129 ArrayRef<LLVM::GEPArg>({0, i}));
1130 auto elemToInt = initBuilder.create<LLVM::PtrToIntOp>(
1131 op.getLoc(), i32Ty, gepElem);
1135 initBuilder.create<LLVM::ZeroOp>(op.getLoc(), voidPtrTy);
1136 auto gepElemSize = initBuilder.create<LLVM::GEPOp>(
1137 op.getLoc(), voidPtrTy, structTy.getBody()[i], elemNull,
1138 ArrayRef<LLVM::GEPArg>({1}));
1139 auto elemSizeToInt = initBuilder.create<LLVM::PtrToIntOp>(
1140 op.getLoc(), i32Ty, gepElemSize);
1143 initBuilder.create<LLVM::CallOp>(
1146 {initStatePtr, sigIndex, elemToInt, elemSizeToInt}));
1149 return WalkResult::advance();
1152 if (sigWalkResult.wasInterrupted())
1155 }
else if (
auto proc = module.lookupSymbol<ProcOp>(instOp.getCallee())) {
1158 auto procStateTy = LLVM::LLVMStructType::getLiteral(
1159 rewriter.getContext(),
1160 {i32Ty, i32Ty, voidPtrTy ,
1161 getProcPersistenceTy(&getDialect(), typeConverter, proc)});
1163 auto zeroC = initBuilder.create<LLVM::ConstantOp>(
1164 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(0));
1167 auto procStateNullPtr =
1168 initBuilder.create<LLVM::ZeroOp>(op->getLoc(), voidPtrTy);
1169 auto procStateGep = initBuilder.create<LLVM::GEPOp>(
1170 op->getLoc(), voidPtrTy, procStateTy, procStateNullPtr,
1171 ArrayRef<LLVM::GEPArg>({1}));
1172 auto procStateSize = initBuilder.create<LLVM::PtrToIntOp>(
1173 op->getLoc(), i64Ty, procStateGep);
1174 std::array<Value, 1> procStateMArgs({procStateSize});
1175 auto procStateMall = initBuilder
1176 .create<LLVM::CallOp>(
1177 op->getLoc(), voidPtrTy,
1182 auto resumeGep = initBuilder.create<LLVM::GEPOp>(
1183 op->getLoc(), voidPtrTy, procStateTy, procStateMall,
1184 ArrayRef<LLVM::GEPArg>({0, 1}));
1185 initBuilder.create<LLVM::StoreOp>(op->getLoc(), zeroC, resumeGep);
1188 auto sensesNullPtr =
1189 initBuilder.create<LLVM::ZeroOp>(op->getLoc(), voidPtrTy);
1190 auto sensesGep = initBuilder.create<LLVM::GEPOp>(
1191 op->getLoc(), voidPtrTy, sensesTy, sensesNullPtr,
1192 ArrayRef<LLVM::GEPArg>({1}));
1194 initBuilder.create<LLVM::PtrToIntOp>(op->getLoc(), i64Ty, sensesGep);
1195 std::array<Value, 1> senseMArgs({sensesSize});
1198 .create<LLVM::CallOp>(op->getLoc(), voidPtrTy,
1203 auto oneB = initBuilder.create<LLVM::ConstantOp>(
1204 op->getLoc(), i1Ty, rewriter.getBoolAttr(
true));
1205 for (
size_t i = 0, e = sensesTy.getNumElements(); i < e; ++i) {
1206 auto senseGep = initBuilder.create<LLVM::GEPOp>(
1207 op->getLoc(), voidPtrTy, i1Ty, sensesMall,
1208 ArrayRef<LLVM::GEPArg>({i}));
1209 initBuilder.create<LLVM::StoreOp>(op->getLoc(), oneB, senseGep);
1213 auto procStateSensesPtr = initBuilder.create<LLVM::GEPOp>(
1214 op->getLoc(), voidPtrTy, procStateTy, procStateMall,
1215 ArrayRef<LLVM::GEPArg>({0, 2}));
1216 initBuilder.create<LLVM::StoreOp>(op->getLoc(), sensesMall,
1217 procStateSensesPtr);
1219 std::array<Value, 3> allocProcArgs({initStatePtr, owner, procStateMall});
1220 initBuilder.create<LLVM::CallOp>(op->getLoc(), std::nullopt,
1225 rewriter.eraseOp(op);
1239 struct SigOpConversion :
public ConvertToLLVMPattern {
1240 explicit SigOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter,
1242 : ConvertToLLVMPattern(llhd::SigOp::getOperationName(), ctx,
1244 sigCounter(sigCounter) {}
1247 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
1248 ConversionPatternRewriter &rewriter)
const override {
1250 SigOpAdaptor transformed(operands);
1257 Value sigTablePtr = op->getParentOfType<LLVM::LLVMFuncOp>().getArgument(2);
1261 rewriter.replaceOpWithNewOp<LLVM::GEPOp>(op, voidPtrTy, sigTy, sigTablePtr,
1262 LLVM::GEPArg(sigCounter));
1278 struct PrbOpConversion :
public ConvertToLLVMPattern {
1279 explicit PrbOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter)
1280 : ConvertToLLVMPattern(llhd::PrbOp::getOperationName(), ctx,
1284 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
1285 ConversionPatternRewriter &rewriter)
const override {
1287 PrbOpAdaptor transformed(operands);
1289 auto prbOp = cast<PrbOp>(op);
1292 auto resTy = prbOp.getType();
1293 auto finalTy = typeConverter->convertType(resTy);
1296 auto sigDetail =
getSignalDetail(rewriter, &getDialect(), op->getLoc(),
1297 transformed.getSignal());
1299 if (resTy.isa<IntegerType>()) {
1302 int resWidth = resTy.getIntOrFloatBitWidth();
1303 int loadWidth = (llvm::divideCeil(resWidth, 8) + 1) * 8;
1307 rewriter.create<LLVM::LoadOp>(op->getLoc(), loadTy, sigDetail[0]);
1310 auto trOff =
adjustBitWidth(op->getLoc(), rewriter, loadTy, sigDetail[1]);
1312 rewriter.create<LLVM::LShrOp>(op->getLoc(), loadTy, loadSig, trOff);
1313 rewriter.replaceOpWithNewOp<LLVM::TruncOp>(op, finalTy, shifted);
1318 if (resTy.isa<hw::ArrayType, hw::StructType>()) {
1319 rewriter.replaceOpWithNewOp<LLVM::LoadOp>(op, finalTy, sigDetail[0]);
1335 struct DrvOpConversion :
public ConvertToLLVMPattern {
1336 explicit DrvOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter)
1337 : ConvertToLLVMPattern(llhd::DrvOp::getOperationName(), ctx,
1341 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
1342 ConversionPatternRewriter &rewriter)
const override {
1344 DrvOpAdaptor transformed(operands);
1346 auto drvOp = cast<DrvOp>(op);
1348 auto module = op->getParentOfType<ModuleOp>();
1351 auto voidTy = getVoidType();
1352 auto voidPtrTy = getVoidPtrType();
1359 voidTy, {voidPtrTy, voidPtrTy, voidPtrTy, i64Ty, i64Ty, i64Ty, i64Ty});
1361 "driveSignal", drvFuncTy);
1364 Value statePtr = op->getParentOfType<LLVM::LLVMFuncOp>().getArgument(0);
1368 auto underlyingTy = drvOp.getValue().getType();
1370 auto underlyingTyConv = typeConverter->convertType(underlyingTy);
1371 auto eightC = rewriter.create<LLVM::ConstantOp>(
1372 op->getLoc(), i64Ty, rewriter.getI64IntegerAttr(8));
1373 auto nullPtr = rewriter.create<LLVM::ZeroOp>(op->getLoc(), voidPtrTy);
1374 auto gepOne = rewriter.create<LLVM::GEPOp>(op->getLoc(), voidPtrTy,
1375 underlyingTyConv, nullPtr,
1376 ArrayRef<LLVM::GEPArg>({1}));
1378 rewriter.create<LLVM::PtrToIntOp>(op->getLoc(), i64Ty, gepOne);
1379 sigWidth = rewriter.create<LLVM::MulOp>(op->getLoc(), toInt, eightC);
1381 sigWidth = rewriter.create<LLVM::ConstantOp>(
1382 op->getLoc(), i64Ty,
1383 rewriter.getI64IntegerAttr(underlyingTy.getIntOrFloatBitWidth()));
1387 if (
auto gate = drvOp.getEnable()) {
1388 auto block = op->getBlock();
1389 auto continueBlock =
1390 rewriter.splitBlock(rewriter.getInsertionBlock(), op->getIterator());
1391 auto drvBlock = rewriter.createBlock(continueBlock);
1392 rewriter.setInsertionPointToEnd(drvBlock);
1393 rewriter.create<LLVM::BrOp>(op->getLoc(), ValueRange(), continueBlock);
1395 rewriter.setInsertionPointToEnd(block);
1396 auto oneC = rewriter.create<LLVM::ConstantOp>(
1397 op->getLoc(), i1Ty, rewriter.getI16IntegerAttr(1));
1398 auto cmp = rewriter.create<LLVM::ICmpOp>(
1399 op->getLoc(), LLVM::ICmpPredicate::eq, transformed.getEnable(), oneC);
1400 rewriter.create<LLVM::CondBrOp>(op->getLoc(), cmp, drvBlock,
1403 rewriter.setInsertionPointToStart(drvBlock);
1406 Type valTy = typeConverter->convertType(transformed.getValue().getType());
1407 Value castVal = typeConverter->materializeTargetConversion(
1408 rewriter, transformed.getValue().getLoc(), valTy,
1409 transformed.getValue());
1411 auto oneConst = rewriter.create<LLVM::ConstantOp>(
1412 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(1));
1416 auto alloca = rewriter.create<LLVM::AllocaOp>(op->getLoc(), voidPtrTy,
1417 valTy, oneConst, 4);
1418 rewriter.create<LLVM::StoreOp>(op->getLoc(), castVal, alloca);
1421 auto realTime = rewriter.create<LLVM::ExtractValueOp>(
1422 op->getLoc(), transformed.getTime(), 0);
1423 auto delta = rewriter.create<LLVM::ExtractValueOp>(
1424 op->getLoc(), transformed.getTime(), 1);
1425 auto eps = rewriter.create<LLVM::ExtractValueOp>(op->getLoc(),
1426 transformed.getTime(), 2);
1429 std::array<Value, 7> args({statePtr, transformed.getSignal(), alloca,
1430 sigWidth, realTime, delta, eps});
1432 rewriter.create<LLVM::CallOp>(op->getLoc(), std::nullopt,
1435 rewriter.eraseOp(op);
1445 struct RegOpConversion :
public ConvertToLLVMPattern {
1446 explicit RegOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter,
1448 : ConvertToLLVMPattern(RegOp::getOperationName(), ctx, typeConverter),
1449 regCounter(regCounter) {}
1452 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
1453 ConversionPatternRewriter &rewriter)
const override {
1454 auto regOp = cast<RegOp>(op);
1455 RegOpAdaptor transformed(operands, op->getAttrDictionary());
1459 auto func = op->getParentOfType<LLVM::LLVMFuncOp>();
1463 size_t triggerIndex = 0;
1464 SmallVector<Value, 4> prevTriggers;
1465 for (
int i = 0, e = regOp.getValues().size(); i < e; ++i) {
1466 auto mode = regOp.getRegModeAt(i);
1467 if (mode == RegMode::both || mode == RegMode::fall ||
1468 mode == RegMode::rise) {
1469 auto gep = rewriter.create<LLVM::GEPOp>(
1470 op->getLoc(), voidPtrTy, i1Ty, func.getArgument(1),
1471 ArrayRef<LLVM::GEPArg>({0, regCounter, triggerIndex++}));
1472 prevTriggers.push_back(
1473 rewriter.create<LLVM::LoadOp>(op->getLoc(), i1Ty, gep));
1474 rewriter.create<LLVM::StoreOp>(op->getLoc(),
1475 transformed.getTriggers()[i], gep);
1480 auto block = op->getBlock();
1481 auto continueBlock = block->splitBlock(op);
1483 auto drvBlock = rewriter.createBlock(continueBlock);
1484 auto valArg = drvBlock->addArgument(transformed.getValues()[0].getType(),
1485 transformed.getValues()[0].getLoc());
1486 auto delayArg = drvBlock->addArgument(transformed.getDelays()[0].getType(),
1487 transformed.getDelays()[0].getLoc());
1488 auto gateArg = drvBlock->addArgument(i1Ty, rewriter.getUnknownLoc());
1491 rewriter.setInsertionPointToStart(drvBlock);
1492 rewriter.create<DrvOp>(op->getLoc(), regOp.getSignal(), valArg, delayArg,
1494 rewriter.create<LLVM::BrOp>(op->getLoc(), ValueRange(), continueBlock);
1496 int j = prevTriggers.size() - 1;
1498 for (
int i = regOp.getValues().size() - 1, e = i; i >= 0; --i) {
1499 auto cmpBlock = rewriter.createBlock(block->getNextNode());
1500 rewriter.setInsertionPointToStart(cmpBlock);
1503 if (regOp.hasGate(i)) {
1504 gate = regOp.getGateAt(i);
1506 gate = rewriter.create<LLVM::ConstantOp>(op->getLoc(), i1Ty,
1507 rewriter.getBoolAttr(
true));
1510 auto drvArgs = std::array<Value, 3>(
1511 {transformed.getValues()[i], transformed.getDelays()[i], gate});
1513 RegMode mode = regOp.getRegModeAt(i);
1517 if (mode == RegMode::low || mode == RegMode::fall) {
1518 rhs = rewriter.create<LLVM::ConstantOp>(op->getLoc(), i1Ty,
1519 rewriter.getBoolAttr(
false));
1520 }
else if (mode == RegMode::high || mode == RegMode::rise) {
1521 rhs = rewriter.create<LLVM::ConstantOp>(op->getLoc(), i1Ty,
1522 rewriter.getBoolAttr(
true));
1529 rewriter.create<LLVM::ICmpOp>(op->getLoc(), LLVM::ICmpPredicate::eq,
1530 transformed.getTriggers()[i], rhs);
1534 if (mode == RegMode::rise || mode == RegMode::fall ||
1535 mode == RegMode::both) {
1537 auto cmpPrev = rewriter.create<LLVM::ICmpOp>(
1538 op->getLoc(), LLVM::ICmpPredicate::ne, transformed.getTriggers()[i],
1540 if (mode == RegMode::both)
1544 rewriter.create<LLVM::AndOp>(op->getLoc(), i1Ty, comp, cmpPrev);
1550 nextBlock = cmpBlock->getNextNode();
1554 nextBlock = continueBlock;
1556 rewriter.create<LLVM::CondBrOp>(op->getLoc(), brCond, drvBlock, drvArgs,
1557 nextBlock, ValueRange());
1560 rewriter.setInsertionPointToEnd(block);
1561 rewriter.create<LLVM::BrOp>(op->getLoc(), ArrayRef<Value>(),
1562 block->getNextNode());
1564 rewriter.eraseOp(op);
1583 struct ConstantTimeOpConversion :
public ConvertToLLVMPattern {
1584 explicit ConstantTimeOpConversion(MLIRContext *ctx,
1585 LLVMTypeConverter &typeConverter)
1586 : ConvertToLLVMPattern(llhd::ConstantTimeOp::getOperationName(), ctx,
1590 matchAndRewrite(Operation *op, ArrayRef<Value> operand,
1591 ConversionPatternRewriter &rewriter)
const override {
1593 auto constOp = cast<ConstantTimeOp>(op);
1595 TimeAttr timeAttr = constOp.getValueAttr();
1598 auto timeTy = typeConverter->convertType(constOp.getResult().getType());
1601 llvm::StringMap<uint64_t> map = {
1602 {
"s", 12}, {
"ms", 9}, {
"us", 6}, {
"ns", 3}, {
"ps", 0}};
1604 std::pow(10, map[timeAttr.getTimeUnit()]) * timeAttr.getTime();
1607 uint64_t delta = timeAttr.getDelta();
1608 uint64_t eps = timeAttr.getEpsilon();
1613 {adjusted, delta, eps});
1614 rewriter.replaceOpWithNewOp<LLVM::ConstantOp>(op, timeTy, denseAttr);
1626 struct SigArraySliceOpConversion
1627 :
public ConvertOpToLLVMPattern<llhd::SigArraySliceOp> {
1628 using ConvertOpToLLVMPattern<llhd::SigArraySliceOp>::ConvertOpToLLVMPattern;
1631 matchAndRewrite(llhd::SigArraySliceOp op, OpAdaptor adaptor,
1632 ConversionPatternRewriter &rewriter)
const override {
1634 Type llvmArrTy = typeConverter->convertType(op.getInputArrayType());
1635 Type inputTy = typeConverter->convertType(op.getInput().getType());
1636 Type lowIndexTy = typeConverter->convertType(op.getLowIndex().getType());
1637 Value castInput = typeConverter->materializeTargetConversion(
1638 rewriter, op->getLoc(), inputTy, op.getInput());
1639 Value castLowIndex = typeConverter->materializeTargetConversion(
1640 rewriter, op->getLoc(), lowIndexTy, op.getLowIndex());
1642 auto sigDetail =
getSignalDetail(rewriter, &getDialect(), op->getLoc(),
1646 sigDetail[0], castLowIndex);
1647 rewriter.replaceOp(op,
createSubSig(&getDialect(), rewriter, op->getLoc(),
1648 sigDetail, adjustedPtr, sigDetail[1]));
1656 struct SigExtractOpConversion
1657 :
public ConvertOpToLLVMPattern<llhd::SigExtractOp> {
1658 using ConvertOpToLLVMPattern<llhd::SigExtractOp>::ConvertOpToLLVMPattern;
1661 matchAndRewrite(llhd::SigExtractOp op, OpAdaptor adaptor,
1662 ConversionPatternRewriter &rewriter)
const override {
1664 Type inputTy = typeConverter->convertType(op.getInput().getType());
1665 Type lowBitTy = typeConverter->convertType(op.getLowBit().getType());
1666 Value castInput = typeConverter->materializeTargetConversion(
1667 rewriter, op->getLoc(), inputTy, op.getInput());
1668 Value castLowBit = typeConverter->materializeTargetConversion(
1669 rewriter, op->getLoc(), lowBitTy, op.getLowBit());
1671 auto sigDetail =
getSignalDetail(rewriter, &getDialect(), op->getLoc(),
1675 rewriter.getI64Type(), castLowBit);
1677 auto adjustedStart =
1678 rewriter.create<LLVM::AddOp>(op->getLoc(), sigDetail[1], zextStart);
1681 op->getLoc(), &getDialect(), rewriter, sigDetail[0], adjustedStart);
1683 rewriter.replaceOp(op,
createSubSig(&getDialect(), rewriter, op->getLoc(),
1684 sigDetail, adjusted.first,
1693 struct SigStructExtractOpConversion
1694 :
public ConvertOpToLLVMPattern<llhd::SigStructExtractOp> {
1695 using ConvertOpToLLVMPattern<
1696 llhd::SigStructExtractOp>::ConvertOpToLLVMPattern;
1699 matchAndRewrite(llhd::SigStructExtractOp op, OpAdaptor adaptor,
1700 ConversionPatternRewriter &rewriter)
const override {
1702 Type llvmStructTy = typeConverter->convertType(op.getStructType());
1703 Type inputTy = typeConverter->convertType(op.getInput().getType());
1704 Value castInput = typeConverter->materializeTargetConversion(
1705 rewriter, op->getLoc(), inputTy, op.getInput());
1707 std::vector<Value> sigDetail =
1711 uint32_t index = HWToLLVMEndianessConverter::llvmIndexOfStructField(
1712 op.getStructType(), op.getField());
1715 op->getLoc(), rewriter, llvmStructTy, sigDetail[0], index);
1717 rewriter.replaceOp(op,
createSubSig(&getDialect(), rewriter, op->getLoc(),
1718 sigDetail, adjusted, sigDetail[1]));
1727 struct SigArrayGetOpConversion
1728 :
public ConvertOpToLLVMPattern<llhd::SigArrayGetOp> {
1729 using ConvertOpToLLVMPattern<llhd::SigArrayGetOp>::ConvertOpToLLVMPattern;
1732 matchAndRewrite(llhd::SigArrayGetOp op, OpAdaptor adaptor,
1733 ConversionPatternRewriter &rewriter)
const override {
1735 auto llvmArrTy = typeConverter->convertType(op.getArrayType());
1736 Type inputTy = typeConverter->convertType(op.getInput().getType());
1737 Type indexTy = typeConverter->convertType(op.getIndex().getType());
1738 Value castInput = typeConverter->materializeTargetConversion(
1739 rewriter, op->getLoc(), inputTy, op.getInput());
1740 Value castIndex = typeConverter->materializeTargetConversion(
1741 rewriter, op->getLoc(), indexTy, op.getIndex());
1743 auto sigDetail =
getSignalDetail(rewriter, &getDialect(), op->getLoc(),
1747 sigDetail[0], castIndex);
1748 rewriter.replaceOp(op,
createSubSig(&getDialect(), rewriter, op->getLoc(),
1749 sigDetail, adjustedPtr, sigDetail[1]));
1763 struct VarOpConversion : ConvertToLLVMPattern {
1764 explicit VarOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter)
1765 : ConvertToLLVMPattern(VarOp::getOperationName(), ctx, typeConverter) {}
1768 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
1769 ConversionPatternRewriter &rewriter)
const override {
1770 VarOpAdaptor transformed(operands);
1773 Type initTy = typeConverter->convertType(transformed.getInit().getType());
1775 auto oneC = rewriter.create<LLVM::ConstantOp>(
1776 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(1));
1777 auto alloca = rewriter.create<LLVM::AllocaOp>(
1780 rewriter.create<LLVM::StoreOp>(op->getLoc(), transformed.getInit(), alloca);
1781 rewriter.replaceOp(op, alloca.getResult());
1790 struct StoreOpConversion : ConvertToLLVMPattern {
1791 explicit StoreOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter)
1792 : ConvertToLLVMPattern(llhd::StoreOp::getOperationName(), ctx,
1796 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
1797 ConversionPatternRewriter &rewriter)
const override {
1798 llhd::StoreOpAdaptor transformed(operands);
1800 rewriter.replaceOpWithNewOp<LLVM::StoreOp>(op, transformed.getValue(),
1801 transformed.getPointer());
1809 OneToOneConvertToLLVMPattern<llhd::LoadOp, LLVM::LoadOp>;
1816 struct LLHDToLLVMLoweringPass
1817 :
public ConvertLLHDToLLVMBase<LLHDToLLVMLoweringPass> {
1818 void runOnOperation()
override;
1825 size_t ®Counter) {
1826 MLIRContext *ctx = converter.getDialect()->getContext();
1829 patterns.add<ConstantTimeOpConversion>(ctx, converter);
1832 patterns.add<SigExtractOpConversion, SigArraySliceOpConversion,
1833 SigArrayGetOpConversion, SigStructExtractOpConversion>(
1837 patterns.add<ProcOpConversion, WaitOpConversion, HaltOpConversion>(ctx,
1839 patterns.add<EntityOpConversion>(ctx, converter, sigCounter, regCounter);
1842 patterns.add<PrbOpConversion, DrvOpConversion>(ctx, converter);
1843 patterns.add<SigOpConversion>(ctx, converter, sigCounter);
1844 patterns.add<RegOpConversion>(ctx, converter, regCounter);
1847 patterns.add<VarOpConversion, StoreOpConversion>(ctx, converter);
1852 converter.addConversion(
1854 converter.addConversion(
1856 converter.addConversion(
1860 void LLHDToLLVMLoweringPass::runOnOperation() {
1867 size_t sigCounter = 0;
1870 size_t regCounter = 0;
1872 RewritePatternSet
patterns(&getContext());
1873 auto converter = mlir::LLVMTypeConverter(&getContext());
1881 patterns.add<InstOpConversion>(&getContext(), converter);
1883 LLVMConversionTarget target(getContext());
1884 target.addIllegalOp<InstOp>();
1885 target.addLegalOp<UnrealizedConversionCastOp>();
1886 cf::populateControlFlowToLLVMConversionPatterns(converter,
patterns);
1887 arith::populateArithToLLVMConversionPatterns(converter,
patterns);
1891 applyPartialConversion(getOperation(), target, std::move(
patterns))))
1892 signalPassFailure();
1896 populateFuncToLLVMConversionPatterns(converter,
patterns);
1901 DenseMap<std::pair<Type, ArrayAttr>, LLVM::GlobalOp> constAggregateGlobalsMap;
1903 constAggregateGlobalsMap);
1906 arith::populateArithToLLVMConversionPatterns(converter,
patterns);
1908 target.addLegalDialect<LLVM::LLVMDialect>();
1909 target.addLegalOp<ModuleOp>();
1912 if (failed(applyFullConversion(getOperation(), target, std::move(
patterns))))
1913 signalPassFailure();
1917 mlir::populateReconcileUnrealizedCastsPatterns(
patterns);
1918 target.addIllegalOp<UnrealizedConversionCastOp>();
1921 if (failed(applyFullConversion(getOperation(), target, std::move(
patterns))))
1922 signalPassFailure();
1927 return std::make_unique<LLHDToLLVMLoweringPass>();
MlirType uint64_t numElements
static Value recursiveCloneInit(OpBuilder &initBuilder, IRMapping &mapping, Value init)
Recursively clone the init origin of a sig operation into the init function, up to the initial consta...
static void insertPersistence(const TypeConverter *converter, ConversionPatternRewriter &rewriter, LLVM::LLVMDialect *dialect, Location loc, ProcOp &proc, Type &stateTy, LLVM::LLVMFuncOp &converted, Operation *splitEntryBefore)
Insert the blocks and operations needed to persist values across suspension, as well as ones needed t...
static Value shiftStructuredSigPointer(Location loc, ConversionPatternRewriter &rewriter, Type elemTy, Value pointer, LLVM::GEPArg index)
Shift the pointer of a structured-type (array or struct) signal, to change its view as if the desired...
static Value shiftArraySigPointer(Location loc, ConversionPatternRewriter &rewriter, Type arrTy, Value pointer, LLVM::GEPArg index)
Shift the pointer of an array-typed signal, to change its view as if the desired slice/element was ex...
static Type convertSigType(SigType type, LLVMTypeConverter &converter)
static void persistValue(LLVM::LLVMDialect *dialect, Location loc, const TypeConverter *converter, ConversionPatternRewriter &rewriter, Type stateTy, int &i, Value state, Value persist)
Persist a Value by storing it into the process persistence table, and substituting the uses that esca...
static Value gepPersistenceState(LLVM::LLVMDialect *dialect, Location loc, ConversionPatternRewriter &rewriter, Type stateTy, int index, Value state)
Insert a GEP operation to the pointer of the i-th value in the process persistence table.
static Value getGlobalString(Location loc, OpBuilder &builder, const TypeConverter *typeConverter, LLVM::GlobalOp &str)
Get an existing global string.
static bool isWaitDestArg(WaitOp op, Value val)
Returns true if the given value is passed as an argument to the destination block of the given WaitOp...
static bool isArrayOrStruct(Type type)
Check if the given type is either of LLHD's ArrayType, StructType, or LLVM array or struct type.
static Type getLLVMSigType(LLVM::LLVMDialect *dialect)
Return the LLVM type used to represent a signal.
static LLVM::LLVMFuncOp getOrInsertFunction(ModuleOp &module, ConversionPatternRewriter &rewriter, Location loc, std::string name, Type signature, bool insertBodyAndTerminator=false)
Looks up a symbol and inserts a new functino at the beginning of the module's region in case the func...
static void insertComparisonBlock(ConversionPatternRewriter &rewriter, LLVM::LLVMDialect *dialect, Location loc, Region *body, Value resumeIdx, int currIdx, Block *trueDest, ValueRange trueDestArgs, Block *falseDest=nullptr)
Insert a comparison block that either jumps to the trueDest block, if the resume index mathces the cu...
static Value zextByOne(Location loc, ConversionPatternRewriter &rewriter, Value value)
Create a zext operation by one bit on the given value.
static std::pair< Value, Value > shiftIntegerSigPointer(Location loc, LLVM::LLVMDialect *dialect, ConversionPatternRewriter &rewriter, Value pointer, Value index)
Shift an integer signal pointer to obtain a view of the underlying value as if it was shifted.
static Type convertTimeType(TimeType type, LLVMTypeConverter &converter)
static Type convertPtrType(PtrType type, LLVMTypeConverter &converter)
static Value adjustBitWidth(Location loc, ConversionPatternRewriter &rewriter, Type targetTy, Value value)
Adjust the bithwidth of value to be the same as targetTy's bitwidth.
static unsigned getIndexOfOperandResult(Operation *op, Value result)
OneToOneConvertToLLVMPattern< llhd::LoadOp, LLVM::LoadOp > LoadOpConversion
static std::vector< Value > getSignalDetail(ConversionPatternRewriter &rewriter, LLVM::LLVMDialect *dialect, Location loc, Value signal, bool extractIndices=false)
Extract the details from the given signal struct.
static LLVM::LLVMStructType getRegStateTy(LLVM::LLVMDialect *dialect, Operation *entity)
Return a struct type of arrays containing one entry for each RegOp condition that require more than o...
static Type getProcPersistenceTy(LLVM::LLVMDialect *dialect, const TypeConverter *converter, ProcOp &proc)
Gather the types of values that are used outside of the block they're defined in.
static Value createSubSig(LLVM::LLVMDialect *dialect, ConversionPatternRewriter &rewriter, Location loc, std::vector< Value > originDetail, Value newPtr, Value newOffset)
Create a subsignal struct.
A namespace that is used to store existing names and generate new names in some scope within the IR.
void add(SymbolCache &symCache)
SymbolCache initializer; initialize from every key that is convertible to a StringAttr in the SymbolC...
void addDefinitions(mlir::Operation *top)
Populate the symbol cache with all symbol-defining operations within the 'top' operation.
Default symbol cache implementation; stores associations between names (StringAttr's) to mlir::Operat...
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
void populateHWToLLVMConversionPatterns(mlir::LLVMTypeConverter &converter, RewritePatternSet &patterns, Namespace &globals, DenseMap< std::pair< Type, ArrayAttr >, mlir::LLVM::GlobalOp > &constAggregateGlobalsMap)
Get the HW to LLVM conversion patterns.
void populateCombToArithConversionPatterns(TypeConverter &converter, RewritePatternSet &patterns)
void populateCombToLLVMConversionPatterns(mlir::LLVMTypeConverter &converter, RewritePatternSet &patterns)
Get the Comb to LLVM conversion patterns.
void populateHWToLLVMTypeConversions(mlir::LLVMTypeConverter &converter)
Get the HW to LLVM type conversions.
void populateLLHDToLLVMTypeConversions(mlir::LLVMTypeConverter &converter)
Get the LLHD to LLVM type conversions.
std::unique_ptr< OperationPass< ModuleOp > > createConvertLLHDToLLVMPass()
Create an LLHD to LLVM conversion pass.
void populateLLHDToLLVMConversionPatterns(mlir::LLVMTypeConverter &converter, RewritePatternSet &patterns, size_t &sigCounter, size_t ®Counter)
Get the LLHD to LLVM conversion patterns.