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>(
52 auto idx =
builder.create<LLVM::ConstantOp>(loc, i32Ty,
54 std::array<Value, 2> idxs({idx, idx});
55 return builder.create<LLVM::GEPOp>(loc, voidPtrTy, addr, idxs);
62 static LLVM::LLVMFuncOp
64 Location loc, std::string name, Type signature,
65 bool insertBodyAndTerminator =
false) {
66 auto func = module.lookupSymbol<LLVM::LLVMFuncOp>(name);
68 OpBuilder moduleBuilder(module.getBodyRegion());
69 func = moduleBuilder.create<LLVM::LLVMFuncOp>(loc, name, signature);
70 if (insertBodyAndTerminator) {
72 OpBuilder b(func.getBody());
73 b.create<LLVM::ReturnOp>(loc, ValueRange());
84 return LLVM::LLVMStructType::getLiteral(dialect->getContext(),
85 {voidPtrTy, i64Ty, i64Ty, i64Ty});
91 LLVM::LLVMDialect *dialect,
92 Location loc, Value signal,
93 bool extractIndices =
false) {
99 std::vector<Value> result;
102 auto zeroC = rewriter.create<LLVM::ConstantOp>(loc, i32Ty,
103 rewriter.getI32IntegerAttr(0));
104 auto oneC = rewriter.create<LLVM::ConstantOp>(loc, i32Ty,
105 rewriter.getI32IntegerAttr(1));
109 signal, ArrayRef<Value>({zeroC, zeroC}));
110 result.push_back(rewriter.create<LLVM::LoadOp>(loc, voidPtrTy, sigPtrPtr));
114 signal, ArrayRef<Value>({zeroC, oneC}));
115 result.push_back(rewriter.create<LLVM::LoadOp>(loc, i64Ty, offsetPtr));
118 if (extractIndices) {
119 auto twoC = rewriter.create<LLVM::ConstantOp>(
120 loc, i32Ty, rewriter.getI32IntegerAttr(2));
121 auto threeC = rewriter.create<LLVM::ConstantOp>(
122 loc, i32Ty, rewriter.getI32IntegerAttr(3));
126 signal, ArrayRef<Value>({zeroC, twoC}));
127 result.push_back(rewriter.create<LLVM::LoadOp>(loc, i64Ty, instIndexPtr));
129 auto globalIndexPtr =
131 signal, ArrayRef<Value>({zeroC, threeC}));
132 result.push_back(rewriter.create<LLVM::LoadOp>(loc, i64Ty, globalIndexPtr));
140 ConversionPatternRewriter &rewriter, Location loc,
141 std::vector<Value> originDetail, Value newPtr,
147 auto sigUndef = rewriter.create<LLVM::UndefOp>(loc, sigTy);
149 rewriter.create<LLVM::InsertValueOp>(loc, sigUndef, newPtr, 0);
150 auto storeSubOffset =
151 rewriter.create<LLVM::InsertValueOp>(loc, storeSubPtr, newOffset, 1);
152 auto storeSubInstIndex = rewriter.create<LLVM::InsertValueOp>(
153 loc, storeSubOffset, originDetail[2], 2);
154 auto storeSubGlobalIndex = rewriter.create<LLVM::InsertValueOp>(
155 loc, storeSubInstIndex, originDetail[3], 3);
158 auto oneC = rewriter.create<LLVM::ConstantOp>(loc, i32Ty,
159 rewriter.getI32IntegerAttr(1));
160 auto allocaSubSig = rewriter.create<LLVM::AllocaOp>(
162 rewriter.create<LLVM::StoreOp>(loc, storeSubGlobalIndex, allocaSubSig);
170 for (
auto arg : op.getDestOps()) {
180 for (
auto user : op->getUsers()) {
181 if (
auto wait = dyn_cast<WaitOp>(user))
189 auto castTy = ty.cast<LLVM::LLVMPointerType>();
190 return castTy.getElementType();
197 const TypeConverter *converter, ProcOp &proc) {
198 SmallVector<Type, 3> types = SmallVector<Type, 3>();
199 proc.walk([&](Operation *op) ->
void {
200 if (op->isUsedOutsideOfBlock(op->getBlock()) ||
isWaitDestArg(op)) {
201 auto ty = op->getResult(0).getType();
202 auto convertedTy = converter->convertType(ty);
203 if (ty.isa<PtrType, SigType>()) {
205 types.push_back(unwrapLLVMPtr(convertedTy));
208 types.push_back(convertedTy);
214 for (
auto &block : proc.getBlocks()) {
216 if (block.isEntryBlock())
219 for (
auto arg : block.getArguments()) {
220 if (arg.isUsedOutsideOfBlock(&block)) {
221 types.push_back(converter->convertType(arg.getType()));
226 return LLVM::LLVMStructType::getLiteral(dialect->getContext(), types);
233 LLVM::LLVMDialect *dialect, Location loc,
234 Region *body, Value resumeIdx,
int currIdx,
235 Block *trueDest, ValueRange trueDestArgs,
236 Block *falseDest =
nullptr) {
238 auto secondBlock = ++body->begin();
239 auto newBlock = rewriter.createBlock(body, secondBlock);
240 auto cmpIdx = rewriter.create<LLVM::ConstantOp>(
241 loc, i32Ty, rewriter.getI32IntegerAttr(currIdx));
242 auto cmpRes = rewriter.create<LLVM::ICmpOp>(loc, LLVM::ICmpPredicate::eq,
248 falseDest = &*secondBlock;
250 rewriter.create<LLVM::CondBrOp>(loc, cmpRes, trueDest, trueDestArgs,
251 falseDest, ValueRange());
254 auto entryTer = body->front().getTerminator();
255 entryTer->setSuccessor(newBlock, 0);
261 ConversionPatternRewriter &rewriter,
262 Type elementTy,
int index, Value state) {
264 auto zeroC = rewriter.create<LLVM::ConstantOp>(loc, i32Ty,
265 rewriter.getI32IntegerAttr(0));
266 auto threeC = rewriter.create<LLVM::ConstantOp>(
267 loc, i32Ty, rewriter.getI32IntegerAttr(3));
268 auto indC = rewriter.create<LLVM::ConstantOp>(
269 loc, i32Ty, rewriter.getI32IntegerAttr(index));
270 return rewriter.create<LLVM::GEPOp>(
272 ArrayRef<Value>({zeroC, threeC, indC}));
279 const TypeConverter *converter,
280 ConversionPatternRewriter &rewriter, Type stateTy,
281 int &i, Value state, Value persist) {
282 auto elemTy = stateTy.cast<LLVM::LLVMStructType>()
284 .cast<LLVM::LLVMStructType>()
287 if (
auto arg = persist.dyn_cast<BlockArgument>()) {
288 rewriter.setInsertionPointToStart(arg.getParentBlock());
290 rewriter.setInsertionPointAfter(persist.getDefiningOp());
293 Value convPersist = converter->materializeTargetConversion(
294 rewriter, loc, converter->convertType(persist.getType()), {persist});
299 if (
auto ptr = persist.getType().dyn_cast<PtrType>()) {
301 auto elemTy = converter->convertType(ptr.getUnderlyingType());
302 toStore = rewriter.create<LLVM::LoadOp>(loc, elemTy, convPersist);
303 }
else if (persist.getType().isa<SigType>()) {
305 toStore = rewriter.create<LLVM::LoadOp>(loc,
getLLVMSigType(dialect),
309 toStore = convPersist;
312 rewriter.create<LLVM::StoreOp>(loc, toStore, gep0);
316 for (
auto &use : llvm::make_early_inc_range(persist.getUses())) {
317 auto user = use.getOwner();
318 if (persist.getType().isa<PtrType>() && user != toStore.getDefiningOp() &&
319 user != convPersist.getDefiningOp() &&
320 persist.getParentBlock() == user->getBlock()) {
325 }
else if (persist.getParentBlock() != user->getBlock() ||
326 (isa<WaitOp>(user) &&
331 if (isa<WaitOp>(user) &&
isWaitDestArg(cast<WaitOp>(user), persist))
332 rewriter.setInsertionPoint(
333 user->getParentRegion()->front().getTerminator());
335 rewriter.setInsertionPointToStart(user->getBlock());
340 if (persist.getType().isa<PtrType, SigType>()) {
343 auto load1 = rewriter.create<LLVM::LoadOp>(loc, elemTy, gep1);
355 ConversionPatternRewriter &rewriter,
356 LLVM::LLVMDialect *dialect, Location loc,
357 ProcOp &proc, Type &stateTy,
358 LLVM::LLVMFuncOp &converted,
359 Operation *splitEntryBefore) {
362 auto &firstBB = converted.getBody().front();
367 rewriter.splitBlock(&firstBB, splitEntryBefore->getIterator());
371 rewriter.setInsertionPointToEnd(&firstBB);
372 rewriter.create<LLVM::BrOp>(loc, ValueRange(), splitFirst);
375 rewriter.setInsertionPoint(firstBB.getTerminator());
376 auto zeroC = rewriter.create<LLVM::ConstantOp>(loc, i32Ty,
377 rewriter.getI32IntegerAttr(0));
378 auto oneC = rewriter.create<LLVM::ConstantOp>(loc, i32Ty,
379 rewriter.getI32IntegerAttr(1));
380 auto gep = rewriter.create<LLVM::GEPOp>(
382 ArrayRef<Value>({zeroC, oneC}));
384 auto larg = rewriter.create<LLVM::LoadOp>(loc, i32Ty, gep);
386 auto body = &converted.getBody();
389 auto abortBlock = rewriter.createBlock(body, body->end());
390 rewriter.create<LLVM::ReturnOp>(loc, ValueRange());
396 ValueRange(), abortBlock);
405 converted.walk([&](Operation *op) ->
void {
406 if ((op->isUsedOutsideOfBlock(op->getBlock()) ||
isWaitDestArg(op)) &&
407 op->getResult(0) != larg.getResult()) {
408 persistValue(dialect, loc, converter, rewriter, stateTy, i,
409 converted.getArgument(1), op->getResult(0));
413 if (
auto wait = dyn_cast<WaitOp>(op)) {
415 wait.getDest(), wait.getDestOps());
418 rewriter.setInsertionPoint(op);
419 auto procState = op->getParentOfType<LLVM::LLVMFuncOp>().getArgument(1);
420 auto resumeIdxC = rewriter.create<LLVM::ConstantOp>(
421 loc, i32Ty, rewriter.getI32IntegerAttr(waitInd));
422 auto resumeIdxPtr = rewriter.create<LLVM::GEPOp>(
424 ArrayRef<Value>({zeroC, oneC}));
425 rewriter.create<LLVM::StoreOp>(op->getLoc(), resumeIdxC, resumeIdxPtr);
430 for (
auto &block : converted.getBlocks()) {
432 if (block.isEntryBlock())
435 for (
auto arg : block.getArguments()) {
436 if (arg.isUsedOutsideOfBlock(&block)) {
437 persistValue(dialect, loc, converter, rewriter, stateTy, i,
438 converted.getArgument(1), arg);
449 SmallVector<Type, 4> types;
450 entity->walk([&](RegOp op) {
452 for (
size_t i = 0; i < op.getModes().
size(); ++i) {
453 auto mode = op.getRegModeAt(i);
454 if (mode == RegMode::fall || mode == RegMode::rise ||
455 mode == RegMode::both)
462 return LLVM::LLVMStructType::getLiteral(dialect->getContext(), types);
468 static Value
zextByOne(Location loc, ConversionPatternRewriter &rewriter,
470 auto valueTy = value.getType();
472 valueTy.getIntOrFloatBitWidth() + 1);
473 return rewriter.create<LLVM::ZExtOp>(loc, zextTy, value);
478 Type targetTy, Value value) {
479 auto valueWidth = value.getType().getIntOrFloatBitWidth();
480 auto targetWidth = targetTy.getIntOrFloatBitWidth();
482 if (valueWidth < targetWidth)
483 return rewriter.create<LLVM::ZExtOp>(loc, targetTy, value);
485 if (valueWidth > targetWidth)
486 return rewriter.create<LLVM::TruncOp>(loc, targetTy, value);
492 for (
unsigned j = 0, e = op->getNumResults(); j < e; ++j) {
493 if (result == result.getDefiningOp()->getResult(j))
497 "no way to recurse to an operation that does not return any value");
506 SmallVector<Value> clonedOperands;
507 Operation *initOp = init.getDefiningOp();
512 if (!initOp || isa<llhd::PrbOp>(initOp))
515 for (
size_t i = 0, e = initOp->getNumOperands(); i < e; ++i) {
516 Value operand = initOp->getOperand(i);
521 if (
auto memorizedOperand = mapping.lookupOrNull(operand)) {
522 clonedOperands.push_back(memorizedOperand);
531 mapping.map(operand, clonedOperand);
532 clonedOperands.push_back(clonedOperand);
535 Operation *clone = initOp->clone();
536 clone->setOperands(clonedOperands);
541 return initBuilder.insert(clone)->getResult(index);
547 return type.isa<LLVM::LLVMArrayType, LLVM::LLVMStructType, hw::ArrayType,
553 static std::pair<Value, Value>
555 ConversionPatternRewriter &rewriter, Value pointer,
560 auto ptrToInt = rewriter.create<LLVM::PtrToIntOp>(loc, i64Ty, pointer);
561 auto const8 = rewriter.create<LLVM::ConstantOp>(
562 loc, index.getType(), rewriter.getI64IntegerAttr(8));
563 auto ptrOffset = rewriter.create<LLVM::UDivOp>(loc, index, const8);
564 auto shiftedPtr = rewriter.create<LLVM::AddOp>(loc, ptrToInt, ptrOffset);
565 auto newPtr = rewriter.create<LLVM::IntToPtrOp>(loc, voidPtrTy, shiftedPtr);
568 auto bitOffset = rewriter.create<LLVM::URemOp>(loc, index, const8);
570 return std::make_pair(newPtr, bitOffset);
576 ConversionPatternRewriter &rewriter,
577 Type structTy, Type elemPtrTy,
578 Value pointer, Value index) {
579 auto dialect = &structTy.getDialect();
583 auto zeroC = rewriter.create<LLVM::ConstantOp>(loc, i32Ty,
584 rewriter.getI32IntegerAttr(0));
585 auto bitcastToArr = rewriter.create<LLVM::BitcastOp>(
587 auto gep = rewriter.create<LLVM::GEPOp>(loc, elemPtrTy, bitcastToArr,
588 ArrayRef<Value>({zeroC, index}));
589 return rewriter.create<LLVM::BitcastOp>(loc, voidPtrTy, gep);
595 ConversionPatternRewriter &rewriter,
596 Type arrTy, Value pointer, Value index) {
598 arrTy.cast<LLVM::LLVMArrayType>().getElementType());
599 auto zextIndex =
zextByOne(loc, rewriter, index);
609 auto &context = converter.getContext();
613 &context, {voidPtrTy, i64Ty, i64Ty, i64Ty}));
623 converter.convertType(type.getUnderlyingType()));
635 struct EntityOpConversion :
public ConvertToLLVMPattern {
636 explicit EntityOpConversion(MLIRContext *ctx,
637 LLVMTypeConverter &typeConverter,
638 size_t &sigCounter,
size_t ®Counter)
639 : ConvertToLLVMPattern(llhd::EntityOp::getOperationName(), ctx,
641 sigCounter(sigCounter), regCounter(regCounter) {}
644 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
645 ConversionPatternRewriter &rewriter)
const override {
647 EntityOpAdaptor transformed(operands);
649 auto entityOp = cast<EntityOp>(op);
652 auto voidTy = getVoidType();
653 auto voidPtrTy = getVoidPtrType();
656 auto entityStatePtrTy =
663 LLVMTypeConverter::SignatureConversion intermediate(
664 entityOp.getNumArguments());
666 intermediate.addInputs(std::array<Type, 3>(
668 for (
size_t i = 0, e = entityOp.getNumArguments(); i < e; ++i)
669 intermediate.addInputs(i, voidTy);
670 rewriter.applySignatureConversion(&entityOp.getBody(), intermediate,
673 OpBuilder bodyBuilder =
674 OpBuilder::atBlockBegin(&entityOp.getBlocks().front());
675 LLVMTypeConverter::SignatureConversion
final(
676 intermediate.getConvertedTypes().size());
677 final.addInputs(0, voidPtrTy);
678 final.addInputs(1, entityStatePtrTy);
683 sigCounter = entityOp.getNumArguments();
684 for (
size_t i = 0; i < sigCounter; ++i) {
686 auto index = bodyBuilder.create<LLVM::ConstantOp>(
687 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(i));
688 auto gep = bodyBuilder.create<LLVM::GEPOp>(
690 entityOp.getArgument(2), ArrayRef<Value>(index));
692 final.remapInput(i + 3, gep.getResult());
695 rewriter.applySignatureConversion(&entityOp.getBody(),
final,
704 auto llvmFunc = rewriter.create<LLVM::LLVMFuncOp>(
705 op->getLoc(), entityOp.getName(), funcTy);
708 rewriter.setInsertionPointToEnd(&entityOp.getBlocks().front());
709 rewriter.create<LLVM::ReturnOp>(op->getLoc(), ValueRange{});
712 rewriter.inlineRegionBefore(entityOp.getBody(), llvmFunc.getBody(),
716 rewriter.eraseOp(op);
731 struct ProcOpConversion :
public ConvertToLLVMPattern {
732 explicit ProcOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter)
733 : ConvertToLLVMPattern(ProcOp::getOperationName(), ctx, typeConverter) {}
736 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
737 ConversionPatternRewriter &rewriter)
const override {
738 auto procOp = cast<ProcOp>(op);
741 ProcOpAdaptor transformed(operands);
744 auto voidTy = getVoidType();
745 auto voidPtrTy = getVoidPtrType();
750 auto stateTy = LLVM::LLVMStructType::getLiteral(
751 rewriter.getContext(),
754 getProcPersistenceTy(&getDialect(), typeConverter, procOp)});
759 auto &firstOp = op->getRegion(0).front().front();
763 LLVMTypeConverter::SignatureConversion intermediate(
764 procOp.getNumArguments());
766 std::array<Type, 3> procArgTys({voidPtrTy,
769 intermediate.addInputs(procArgTys);
770 for (
size_t i = 0, e = procOp.getNumArguments(); i < e; ++i)
771 intermediate.addInputs(i, voidTy);
772 rewriter.applySignatureConversion(&procOp.getBody(), intermediate,
776 OpBuilder bodyBuilder =
777 OpBuilder::atBlockBegin(&procOp.getBlocks().front());
778 LLVMTypeConverter::SignatureConversion
final(
779 intermediate.getConvertedTypes().size());
780 final.addInputs(0, voidPtrTy);
784 for (
size_t i = 0, e = procOp.getNumArguments(); i < e; ++i) {
786 auto index = bodyBuilder.create<LLVM::ConstantOp>(
787 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(i));
788 auto gep = bodyBuilder.create<LLVM::GEPOp>(
790 procOp.getArgument(2), ArrayRef<Value>({index}));
793 final.remapInput(i + 3, gep.getResult());
801 auto llvmFunc = rewriter.create<LLVM::LLVMFuncOp>(op->getLoc(),
802 procOp.getName(), funcTy);
805 rewriter.inlineRegionBefore(procOp.getBody(), llvmFunc.getBody(),
809 procOp, stateTy, llvmFunc, &firstOp);
813 if (failed(rewriter.convertRegionTypes(&llvmFunc.getBody(), *typeConverter,
818 rewriter.eraseOp(op);
829 struct HaltOpConversion :
public ConvertToLLVMPattern {
830 explicit HaltOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter)
831 : ConvertToLLVMPattern(HaltOp::getOperationName(), ctx, typeConverter) {}
834 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
835 ConversionPatternRewriter &rewriter)
const override {
839 auto llvmFunc = op->getParentOfType<LLVM::LLVMFuncOp>();
840 auto procState = llvmFunc.getArgument(1);
841 auto senseTableTy = procState.getType()
842 .cast<LLVM::LLVMPointerType>()
844 .cast<LLVM::LLVMStructType>()
846 .cast<LLVM::LLVMPointerType>()
848 .cast<LLVM::LLVMArrayType>();
851 auto zeroC = rewriter.create<LLVM::ConstantOp>(
852 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(0));
853 auto twoC = rewriter.create<LLVM::ConstantOp>(
854 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(2));
855 auto sensePtrGep = rewriter.create<LLVM::GEPOp>(
858 procState, ArrayRef<Value>({zeroC, twoC}));
859 auto sensePtr = rewriter.create<LLVM::LoadOp>(
863 for (
size_t i = 0, e = senseTableTy.getNumElements(); i < e; ++i) {
864 auto indC = rewriter.create<LLVM::ConstantOp>(
865 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(i));
866 auto zeroB = rewriter.create<LLVM::ConstantOp>(
867 op->getLoc(), i1Ty, rewriter.getI32IntegerAttr(0));
868 auto senseElemPtr = rewriter.create<LLVM::GEPOp>(
870 ArrayRef<Value>({zeroC, indC}));
871 rewriter.create<LLVM::StoreOp>(op->getLoc(), zeroB, senseElemPtr);
874 rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, ValueRange());
884 struct WaitOpConversion :
public ConvertToLLVMPattern {
885 explicit WaitOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter)
886 : ConvertToLLVMPattern(WaitOp::getOperationName(), ctx, typeConverter) {}
889 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
890 ConversionPatternRewriter &rewriter)
const override {
891 auto waitOp = cast<WaitOp>(op);
892 WaitOpAdaptor transformed(operands, op->getAttrDictionary());
893 auto llvmFunc = op->getParentOfType<LLVM::LLVMFuncOp>();
895 auto voidTy = getVoidType();
896 auto voidPtrTy = getVoidPtrType();
903 voidTy, {voidPtrTy, voidPtrTy, i64Ty, i64Ty, i64Ty});
904 auto module = op->getParentOfType<ModuleOp>();
906 "llhdSuspend", llhdSuspendTy);
908 auto statePtr = llvmFunc.getArgument(0);
909 auto procState = llvmFunc.getArgument(1);
910 auto procStateTy = procState.getType();
911 auto senseTableTy = procStateTy.cast<LLVM::LLVMPointerType>()
913 .cast<LLVM::LLVMStructType>()
915 .cast<LLVM::LLVMPointerType>()
919 auto zeroC = rewriter.create<LLVM::ConstantOp>(
920 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(0));
921 auto twoC = rewriter.create<LLVM::ConstantOp>(
922 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(2));
923 auto sensePtrGep = rewriter.create<LLVM::GEPOp>(
926 procState, ArrayRef<Value>({zeroC, twoC}));
927 auto sensePtr = rewriter.create<LLVM::LoadOp>(
931 if (waitOp.getObs().size() <
932 senseTableTy.cast<LLVM::LLVMArrayType>().getNumElements()) {
933 auto zeroB = rewriter.create<LLVM::ConstantOp>(
934 op->getLoc(), i1Ty, rewriter.getBoolAttr(
false));
936 e = senseTableTy.cast<LLVM::LLVMArrayType>().getNumElements();
938 auto indC = rewriter.create<LLVM::ConstantOp>(
939 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(i));
940 auto senseElemPtr = rewriter.create<LLVM::GEPOp>(
942 ArrayRef<Value>({zeroC, indC}));
943 rewriter.create<LLVM::StoreOp>(op->getLoc(), zeroB, senseElemPtr);
948 for (
auto observed : transformed.getObs()) {
949 auto instIndexPtr = rewriter.create<LLVM::GEPOp>(
951 ArrayRef<Value>({zeroC, twoC}));
953 rewriter.create<LLVM::LoadOp>(op->getLoc(), i64Ty, instIndexPtr);
954 auto oneB = rewriter.create<LLVM::ConstantOp>(op->getLoc(), i1Ty,
955 rewriter.getBoolAttr(
true));
956 auto senseElementPtr = rewriter.create<LLVM::GEPOp>(
958 ArrayRef<Value>({zeroC, instIndex}));
959 rewriter.create<LLVM::StoreOp>(op->getLoc(), oneB, senseElementPtr);
964 rewriter.create<LLVM::BitcastOp>(op->getLoc(), voidPtrTy, procState);
967 if (waitOp.getTime()) {
968 auto realTime = rewriter.create<LLVM::ExtractValueOp>(
969 op->getLoc(), transformed.getTime(), 0);
970 auto delta = rewriter.create<LLVM::ExtractValueOp>(
971 op->getLoc(), transformed.getTime(), 1);
972 auto eps = rewriter.create<LLVM::ExtractValueOp>(
973 op->getLoc(), transformed.getTime(), 2);
975 std::array<Value, 5> args({statePtr, procStateBC, realTime, delta, eps});
976 rewriter.create<LLVM::CallOp>(op->getLoc(), std::nullopt,
980 rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, ValueRange());
990 struct InstOpConversion :
public ConvertToLLVMPattern {
991 explicit InstOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter)
992 : ConvertToLLVMPattern(InstOp::getOperationName(), ctx, typeConverter) {}
995 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
996 ConversionPatternRewriter &rewriter)
const override {
998 auto instOp = cast<InstOp>(op);
1000 auto module = op->getParentOfType<ModuleOp>();
1001 auto entity = op->getParentOfType<EntityOp>();
1003 auto voidTy = getVoidType();
1004 auto voidPtrTy = getVoidPtrType();
1019 "malloc", mallocSigFuncTy);
1025 i32Ty, {voidPtrTy, i32Ty, voidPtrTy, voidPtrTy, i64Ty});
1027 "allocSignal", allocSigFuncTy);
1032 auto addSigArrElemFuncTy =
1034 auto addSigElemFunc =
1036 "addSigArrayElements", addSigArrElemFuncTy);
1040 auto addSigStructElemFuncTy =
1042 auto addSigStructFunc =
1044 "addSigStructElement", addSigStructElemFuncTy);
1047 auto allocProcFuncTy =
1050 "allocProc", allocProcFuncTy);
1053 auto allocEntityFuncTy =
1056 module, rewriter, op->getLoc(),
"allocEntity", allocEntityFuncTy);
1058 Value initStatePtr = initFunc.getArgument(0);
1061 OpBuilder initBuilder =
1062 OpBuilder::atBlockTerminator(&initFunc.getBody().getBlocks().front());
1065 auto ownerName = entity.getName().str() +
"." + instOp.getName().str();
1070 module.lookupSymbol<LLVM::GlobalOp>(
"instance." + ownerName);
1072 owner = LLVM::createGlobalString(
1073 op->getLoc(), initBuilder,
"instance." + ownerName, ownerName +
'\0',
1074 LLVM::Linkage::Internal,
true);
1075 parentSym = module.lookupSymbol<LLVM::GlobalOp>(
"instance." + ownerName);
1082 if (
auto child = module.lookupSymbol<EntityOp>(instOp.getCallee())) {
1083 auto regStateTy =
getRegStateTy(&getDialect(), child.getOperation());
1087 auto oneC = initBuilder.create<LLVM::ConstantOp>(
1088 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(1));
1090 initBuilder.create<LLVM::NullOp>(op->getLoc(), regStatePtrTy);
1091 auto regGep = initBuilder.create<LLVM::GEPOp>(
1092 op->getLoc(), regStatePtrTy, regNull, ArrayRef<Value>({oneC}));
1094 initBuilder.create<LLVM::PtrToIntOp>(op->getLoc(), i64Ty, regGep);
1097 auto regMall = initBuilder
1098 .create<LLVM::CallOp>(op->getLoc(), voidPtrTy,
1100 ArrayRef<Value>({regSize}))
1102 auto regMallBC = initBuilder.create<LLVM::BitcastOp>(
1103 op->getLoc(), regStatePtrTy, regMall);
1104 auto zeroB = initBuilder.create<LLVM::ConstantOp>(
1105 op->getLoc(), i1Ty, rewriter.getBoolAttr(
false));
1109 e = regStateTy.cast<LLVM::LLVMStructType>().getBody().size();
1111 size_t f = regStateTy.cast<LLVM::LLVMStructType>()
1113 .cast<LLVM::LLVMArrayType>()
1115 for (
size_t j = 0; j < f; ++j) {
1116 auto regIndexC = initBuilder.create<LLVM::ConstantOp>(
1117 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(i));
1118 auto triggerIndexC = initBuilder.create<LLVM::ConstantOp>(
1119 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(j));
1120 auto regGep = initBuilder.create<LLVM::GEPOp>(
1122 ArrayRef<Value>({zeroB, regIndexC, triggerIndexC}));
1123 initBuilder.create<LLVM::StoreOp>(op->getLoc(), zeroB, regGep);
1128 initBuilder.create<LLVM::CallOp>(
1130 ArrayRef<Value>({initStatePtr, owner, regMall}));
1133 int initCounter = 0;
1135 WalkResult sigWalkResult = child.walk([&](SigOp op) -> WalkResult {
1137 auto underlyingTy = typeConverter->convertType(op.getInit().getType());
1139 auto indexConst = initBuilder.create<LLVM::ConstantOp>(
1140 op.getLoc(), i32Ty, rewriter.getI32IntegerAttr(initCounter));
1149 return WalkResult::interrupt();
1151 Value initDefCast = typeConverter->materializeTargetConversion(
1152 initBuilder, initDef.getLoc(),
1153 typeConverter->convertType(initDef.getType()), initDef);
1156 auto oneC = initBuilder.create<LLVM::ConstantOp>(
1157 op.getLoc(), i32Ty, rewriter.getI32IntegerAttr(1));
1158 auto twoC = initBuilder.create<LLVM::ConstantOp>(
1159 op.getLoc(), i64Ty, rewriter.getI32IntegerAttr(2));
1160 auto nullPtr = initBuilder.create<LLVM::NullOp>(
1162 auto sizeGep = initBuilder.create<LLVM::GEPOp>(
1164 ArrayRef<Value>(oneC));
1166 initBuilder.create<LLVM::PtrToIntOp>(op.getLoc(), i64Ty, sizeGep);
1170 initBuilder.create<LLVM::MulOp>(op.getLoc(), i64Ty,
size, twoC);
1171 std::array<Value, 1> margs({mallocSize});
1174 .create<LLVM::CallOp>(op.getLoc(), voidPtrTy,
1179 auto bitcast = initBuilder.create<LLVM::BitcastOp>(
1182 initBuilder.create<LLVM::StoreOp>(op.getLoc(), initDefCast, bitcast);
1187 if (
auto intTy = underlyingTy.dyn_cast<IntegerType>()) {
1188 auto byteWidth = llvm::divideCeil(intTy.getWidth(), 8);
1189 passSize = initBuilder.create<LLVM::ConstantOp>(
1190 op.getLoc(), i64Ty, rewriter.getI64IntegerAttr(byteWidth));
1195 std::array<Value, 5> args(
1196 {initStatePtr, indexConst, owner, mall, passSize});
1199 .create<LLVM::CallOp>(op.getLoc(), i32Ty,
1204 if (
auto arrayTy = underlyingTy.dyn_cast<LLVM::LLVMArrayType>()) {
1205 auto zeroC = initBuilder.create<LLVM::ConstantOp>(
1206 op.getLoc(), i32Ty, rewriter.getI32IntegerAttr(0));
1208 auto numElements = initBuilder.create<LLVM::ConstantOp>(
1210 rewriter.getI32IntegerAttr(arrayTy.getNumElements()));
1213 auto null = initBuilder.create<LLVM::NullOp>(
1215 auto gepFirst = initBuilder.create<LLVM::GEPOp>(
1217 null, ArrayRef<Value>({zeroC, oneC}));
1218 auto toInt = initBuilder.create<LLVM::PtrToIntOp>(op.getLoc(), i32Ty,
1222 initBuilder.create<LLVM::CallOp>(
1224 ArrayRef<Value>({initStatePtr, sigIndex, toInt,
numElements}));
1225 }
else if (
auto structTy =
1226 underlyingTy.dyn_cast<LLVM::LLVMStructType>()) {
1227 auto zeroC = initBuilder.create<LLVM::ConstantOp>(
1228 op.getLoc(), i32Ty, rewriter.getI32IntegerAttr(0));
1230 auto null = initBuilder.create<LLVM::NullOp>(
1232 for (
size_t i = 0, e = structTy.getBody().size(); i < e; ++i) {
1233 auto oneC = initBuilder.create<LLVM::ConstantOp>(
1234 op.getLoc(), i32Ty, rewriter.getI32IntegerAttr(1));
1235 auto indexC = initBuilder.create<LLVM::ConstantOp>(
1236 op.getLoc(), i32Ty, rewriter.getI32IntegerAttr(i));
1239 auto gepElem = initBuilder.create<LLVM::GEPOp>(
1241 null, ArrayRef<Value>({zeroC, indexC}));
1242 auto elemToInt = initBuilder.create<LLVM::PtrToIntOp>(
1243 op.getLoc(), i32Ty, gepElem);
1246 auto elemNull = initBuilder.create<LLVM::NullOp>(
1248 auto gepElemSize = initBuilder.create<LLVM::GEPOp>(
1250 elemNull, ArrayRef<Value>({oneC}));
1251 auto elemSizeToInt = initBuilder.create<LLVM::PtrToIntOp>(
1252 op.getLoc(), i32Ty, gepElemSize);
1255 initBuilder.create<LLVM::CallOp>(
1258 {initStatePtr, sigIndex, elemToInt, elemSizeToInt}));
1261 return WalkResult::advance();
1264 if (sigWalkResult.wasInterrupted())
1267 }
else if (
auto proc = module.lookupSymbol<ProcOp>(instOp.getCallee())) {
1271 auto procStatePtrTy =
1273 rewriter.getContext(),
1274 {i32Ty, i32Ty, sensesPtrTy,
1275 getProcPersistenceTy(&getDialect(), typeConverter, proc)}));
1277 auto zeroC = initBuilder.create<LLVM::ConstantOp>(
1278 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(0));
1279 auto oneC = initBuilder.create<LLVM::ConstantOp>(
1280 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(1));
1281 auto twoC = initBuilder.create<LLVM::ConstantOp>(
1282 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(2));
1285 auto procStateNullPtr =
1286 initBuilder.create<LLVM::NullOp>(op->getLoc(), procStatePtrTy);
1287 auto procStateGep = initBuilder.create<LLVM::GEPOp>(
1288 op->getLoc(), procStatePtrTy, procStateNullPtr,
1289 ArrayRef<Value>({oneC}));
1290 auto procStateSize = initBuilder.create<LLVM::PtrToIntOp>(
1291 op->getLoc(), i64Ty, procStateGep);
1292 std::array<Value, 1> procStateMArgs({procStateSize});
1293 auto procStateMall = initBuilder
1294 .create<LLVM::CallOp>(
1295 op->getLoc(), voidPtrTy,
1299 auto procStateBC = initBuilder.create<LLVM::BitcastOp>(
1300 op->getLoc(), procStatePtrTy, procStateMall);
1303 auto resumeGep = initBuilder.create<LLVM::GEPOp>(
1305 ArrayRef<Value>({zeroC, oneC}));
1306 initBuilder.create<LLVM::StoreOp>(op->getLoc(), zeroC, resumeGep);
1309 auto sensesNullPtr =
1310 initBuilder.create<LLVM::NullOp>(op->getLoc(), sensesPtrTy);
1311 auto sensesGep = initBuilder.create<LLVM::GEPOp>(
1312 op->getLoc(), sensesPtrTy, sensesNullPtr, ArrayRef<Value>({oneC}));
1314 initBuilder.create<LLVM::PtrToIntOp>(op->getLoc(), i64Ty, sensesGep);
1315 std::array<Value, 1> senseMArgs({sensesSize});
1318 .create<LLVM::CallOp>(op->getLoc(), voidPtrTy,
1322 auto sensesBC = initBuilder.create<LLVM::BitcastOp>(
1323 op->getLoc(), sensesPtrTy, sensesMall);
1326 for (
size_t i = 0, e = sensesPtrTy.cast<LLVM::LLVMPointerType>()
1328 .cast<LLVM::LLVMArrayType>()
1331 auto oneB = initBuilder.create<LLVM::ConstantOp>(
1332 op->getLoc(), i1Ty, rewriter.getBoolAttr(
true));
1333 auto gepInd = initBuilder.create<LLVM::ConstantOp>(
1334 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(i));
1335 auto senseGep = initBuilder.create<LLVM::GEPOp>(
1337 ArrayRef<Value>({zeroC, gepInd}));
1338 initBuilder.create<LLVM::StoreOp>(op->getLoc(), oneB, senseGep);
1342 auto procStateSensesPtr = initBuilder.create<LLVM::GEPOp>(
1344 ArrayRef<Value>({zeroC, twoC}));
1345 initBuilder.create<LLVM::StoreOp>(op->getLoc(), sensesBC,
1346 procStateSensesPtr);
1348 std::array<Value, 3> allocProcArgs({initStatePtr, owner, procStateMall});
1349 initBuilder.create<LLVM::CallOp>(op->getLoc(), std::nullopt,
1354 rewriter.eraseOp(op);
1368 struct SigOpConversion :
public ConvertToLLVMPattern {
1369 explicit SigOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter,
1371 : ConvertToLLVMPattern(llhd::SigOp::getOperationName(), ctx,
1373 sigCounter(sigCounter) {}
1376 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
1377 ConversionPatternRewriter &rewriter)
const override {
1379 SigOpAdaptor transformed(operands);
1386 Value sigTablePtr = op->getParentOfType<LLVM::LLVMFuncOp>().getArgument(2);
1389 auto indexConst = rewriter.create<LLVM::ConstantOp>(
1390 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(sigCounter));
1394 rewriter.replaceOpWithNewOp<LLVM::GEPOp>(
1396 ArrayRef<Value>(indexConst));
1411 struct PrbOpConversion :
public ConvertToLLVMPattern {
1412 explicit PrbOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter)
1413 : ConvertToLLVMPattern(llhd::PrbOp::getOperationName(), ctx,
1417 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
1418 ConversionPatternRewriter &rewriter)
const override {
1420 PrbOpAdaptor transformed(operands);
1422 auto prbOp = cast<PrbOp>(op);
1425 auto resTy = prbOp.getType();
1426 auto finalTy = typeConverter->convertType(resTy);
1429 auto sigDetail =
getSignalDetail(rewriter, &getDialect(), op->getLoc(),
1430 transformed.getSignal());
1432 if (resTy.isa<IntegerType>()) {
1435 int resWidth = resTy.getIntOrFloatBitWidth();
1436 int loadWidth = (llvm::divideCeil(resWidth, 8) + 1) * 8;
1439 auto bitcast = rewriter.create<LLVM::BitcastOp>(
1442 rewriter.create<LLVM::LoadOp>(op->getLoc(), loadTy, bitcast);
1445 auto trOff =
adjustBitWidth(op->getLoc(), rewriter, loadTy, sigDetail[1]);
1447 rewriter.create<LLVM::LShrOp>(op->getLoc(), loadTy, loadSig, trOff);
1448 rewriter.replaceOpWithNewOp<LLVM::TruncOp>(op, finalTy, shifted);
1453 if (resTy.isa<hw::ArrayType, hw::StructType>()) {
1454 auto bitcast = rewriter.create<LLVM::BitcastOp>(
1456 rewriter.replaceOpWithNewOp<LLVM::LoadOp>(op, finalTy, bitcast);
1472 struct DrvOpConversion :
public ConvertToLLVMPattern {
1473 explicit DrvOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter)
1474 : ConvertToLLVMPattern(llhd::DrvOp::getOperationName(), ctx,
1478 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
1479 ConversionPatternRewriter &rewriter)
const override {
1481 DrvOpAdaptor transformed(operands);
1483 auto drvOp = cast<DrvOp>(op);
1485 auto module = op->getParentOfType<ModuleOp>();
1488 auto voidTy = getVoidType();
1489 auto voidPtrTy = getVoidPtrType();
1498 i64Ty, i64Ty, i64Ty});
1500 "driveSignal", drvFuncTy);
1503 Value statePtr = op->getParentOfType<LLVM::LLVMFuncOp>().getArgument(0);
1507 auto underlyingTy = drvOp.getValue().getType();
1511 auto oneC = rewriter.create<LLVM::ConstantOp>(
1512 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(1));
1513 auto eightC = rewriter.create<LLVM::ConstantOp>(
1514 op->getLoc(), i64Ty, rewriter.getI64IntegerAttr(8));
1515 auto nullPtr = rewriter.create<LLVM::NullOp>(op->getLoc(), llvmPtrTy);
1516 auto gepOne = rewriter.create<LLVM::GEPOp>(
1517 op->getLoc(), llvmPtrTy, nullPtr, ArrayRef<Value>(oneC));
1519 rewriter.create<LLVM::PtrToIntOp>(op->getLoc(), i64Ty, gepOne);
1520 sigWidth = rewriter.create<LLVM::MulOp>(op->getLoc(), toInt, eightC);
1522 sigWidth = rewriter.create<LLVM::ConstantOp>(
1523 op->getLoc(), i64Ty,
1524 rewriter.getI64IntegerAttr(underlyingTy.getIntOrFloatBitWidth()));
1528 if (
auto gate = drvOp.getEnable()) {
1529 auto block = op->getBlock();
1530 auto continueBlock =
1531 rewriter.splitBlock(rewriter.getInsertionBlock(), op->getIterator());
1532 auto drvBlock = rewriter.createBlock(continueBlock);
1533 rewriter.setInsertionPointToEnd(drvBlock);
1534 rewriter.create<LLVM::BrOp>(op->getLoc(), ValueRange(), continueBlock);
1536 rewriter.setInsertionPointToEnd(block);
1537 auto oneC = rewriter.create<LLVM::ConstantOp>(
1538 op->getLoc(), i1Ty, rewriter.getI16IntegerAttr(1));
1539 auto cmp = rewriter.create<LLVM::ICmpOp>(
1540 op->getLoc(), LLVM::ICmpPredicate::eq, transformed.getEnable(), oneC);
1541 rewriter.create<LLVM::CondBrOp>(op->getLoc(), cmp, drvBlock,
1544 rewriter.setInsertionPointToStart(drvBlock);
1547 Type valTy = typeConverter->convertType(transformed.getValue().getType());
1548 Value castVal = typeConverter->materializeTargetConversion(
1549 rewriter, transformed.getValue().getLoc(), valTy,
1550 transformed.getValue());
1552 auto oneConst = rewriter.create<LLVM::ConstantOp>(
1553 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(1));
1557 auto alloca = rewriter.create<LLVM::AllocaOp>(
1559 rewriter.create<LLVM::StoreOp>(op->getLoc(), castVal, alloca);
1560 auto bc = rewriter.create<LLVM::BitcastOp>(op->getLoc(), voidPtrTy, alloca);
1563 auto realTime = rewriter.create<LLVM::ExtractValueOp>(
1564 op->getLoc(), transformed.getTime(), 0);
1565 auto delta = rewriter.create<LLVM::ExtractValueOp>(
1566 op->getLoc(), transformed.getTime(), 1);
1567 auto eps = rewriter.create<LLVM::ExtractValueOp>(op->getLoc(),
1568 transformed.getTime(), 2);
1571 std::array<Value, 7> args({statePtr, transformed.getSignal(), bc, sigWidth,
1572 realTime, delta, eps});
1574 rewriter.create<LLVM::CallOp>(op->getLoc(), std::nullopt,
1577 rewriter.eraseOp(op);
1587 struct RegOpConversion :
public ConvertToLLVMPattern {
1588 explicit RegOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter,
1590 : ConvertToLLVMPattern(RegOp::getOperationName(), ctx, typeConverter),
1591 regCounter(regCounter) {}
1594 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
1595 ConversionPatternRewriter &rewriter)
const override {
1596 auto regOp = cast<RegOp>(op);
1597 RegOpAdaptor transformed(operands, op->getAttrDictionary());
1602 auto func = op->getParentOfType<LLVM::LLVMFuncOp>();
1606 size_t triggerIndex = 0;
1607 SmallVector<Value, 4> prevTriggers;
1608 for (
int i = 0, e = regOp.getValues().size(); i < e; ++i) {
1609 auto mode = regOp.getRegModeAt(i);
1610 if (mode == RegMode::both || mode == RegMode::fall ||
1611 mode == RegMode::rise) {
1612 auto zeroC = rewriter.create<LLVM::ConstantOp>(
1613 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(0));
1614 auto regIndexC = rewriter.create<LLVM::ConstantOp>(
1615 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(regCounter));
1616 auto triggerIndexC = rewriter.create<LLVM::ConstantOp>(
1617 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(triggerIndex++));
1618 auto gep = rewriter.create<LLVM::GEPOp>(
1620 ArrayRef<Value>({zeroC, regIndexC, triggerIndexC}));
1621 prevTriggers.push_back(
1622 rewriter.create<LLVM::LoadOp>(op->getLoc(), gep));
1623 rewriter.create<LLVM::StoreOp>(op->getLoc(),
1624 transformed.getTriggers()[i], gep);
1629 auto block = op->getBlock();
1630 auto continueBlock = block->splitBlock(op);
1632 auto drvBlock = rewriter.createBlock(continueBlock);
1633 auto valArg = drvBlock->addArgument(transformed.getValues()[0].getType(),
1634 transformed.getValues()[0].getLoc());
1635 auto delayArg = drvBlock->addArgument(transformed.getDelays()[0].getType(),
1636 transformed.getDelays()[0].getLoc());
1637 auto gateArg = drvBlock->addArgument(i1Ty, rewriter.getUnknownLoc());
1640 rewriter.setInsertionPointToStart(drvBlock);
1641 rewriter.create<DrvOp>(op->getLoc(), regOp.getSignal(), valArg, delayArg,
1643 rewriter.create<LLVM::BrOp>(op->getLoc(), ValueRange(), continueBlock);
1645 int j = prevTriggers.size() - 1;
1647 for (
int i = regOp.getValues().size() - 1, e = i; i >= 0; --i) {
1648 auto cmpBlock = rewriter.createBlock(block->getNextNode());
1649 rewriter.setInsertionPointToStart(cmpBlock);
1652 if (regOp.hasGate(i)) {
1653 gate = regOp.getGateAt(i);
1655 gate = rewriter.create<LLVM::ConstantOp>(op->getLoc(), i1Ty,
1656 rewriter.getBoolAttr(
true));
1659 auto drvArgs = std::array<Value, 3>(
1660 {transformed.getValues()[i], transformed.getDelays()[i], gate});
1662 RegMode mode = regOp.getRegModeAt(i);
1666 if (mode == RegMode::low || mode == RegMode::fall) {
1667 rhs = rewriter.create<LLVM::ConstantOp>(op->getLoc(), i1Ty,
1668 rewriter.getBoolAttr(
false));
1669 }
else if (mode == RegMode::high || mode == RegMode::rise) {
1670 rhs = rewriter.create<LLVM::ConstantOp>(op->getLoc(), i1Ty,
1671 rewriter.getBoolAttr(
true));
1678 rewriter.create<LLVM::ICmpOp>(op->getLoc(), LLVM::ICmpPredicate::eq,
1679 transformed.getTriggers()[i], rhs);
1683 if (mode == RegMode::rise || mode == RegMode::fall ||
1684 mode == RegMode::both) {
1686 auto cmpPrev = rewriter.create<LLVM::ICmpOp>(
1687 op->getLoc(), LLVM::ICmpPredicate::ne, transformed.getTriggers()[i],
1689 if (mode == RegMode::both)
1693 rewriter.create<LLVM::AndOp>(op->getLoc(), i1Ty, comp, cmpPrev);
1699 nextBlock = cmpBlock->getNextNode();
1703 nextBlock = continueBlock;
1705 rewriter.create<LLVM::CondBrOp>(op->getLoc(), brCond, drvBlock, drvArgs,
1706 nextBlock, ValueRange());
1709 rewriter.setInsertionPointToEnd(block);
1710 rewriter.create<LLVM::BrOp>(op->getLoc(), ArrayRef<Value>(),
1711 block->getNextNode());
1713 rewriter.eraseOp(op);
1732 struct ConstantTimeOpConversion :
public ConvertToLLVMPattern {
1733 explicit ConstantTimeOpConversion(MLIRContext *ctx,
1734 LLVMTypeConverter &typeConverter)
1735 : ConvertToLLVMPattern(llhd::ConstantTimeOp::getOperationName(), ctx,
1739 matchAndRewrite(Operation *op, ArrayRef<Value> operand,
1740 ConversionPatternRewriter &rewriter)
const override {
1742 auto constOp = cast<ConstantTimeOp>(op);
1744 TimeAttr timeAttr = constOp.getValueAttr();
1747 auto timeTy = typeConverter->convertType(constOp.getResult().getType());
1750 llvm::StringMap<uint64_t> map = {
1751 {
"s", 12}, {
"ms", 9}, {
"us", 6}, {
"ns", 3}, {
"ps", 0}};
1753 std::pow(10, map[timeAttr.getTimeUnit()]) * timeAttr.getTime();
1756 uint64_t delta = timeAttr.getDelta();
1757 uint64_t eps = timeAttr.getEpsilon();
1762 {adjusted, delta, eps});
1763 rewriter.replaceOpWithNewOp<LLVM::ConstantOp>(op, timeTy, denseAttr);
1775 struct SigArraySliceOpConversion
1776 :
public ConvertOpToLLVMPattern<llhd::SigArraySliceOp> {
1777 using ConvertOpToLLVMPattern<llhd::SigArraySliceOp>::ConvertOpToLLVMPattern;
1780 matchAndRewrite(llhd::SigArraySliceOp op, OpAdaptor adaptor,
1781 ConversionPatternRewriter &rewriter)
const override {
1783 Type llvmArrTy = typeConverter->convertType(op.getInputArrayType());
1784 Type inputTy = typeConverter->convertType(op.getInput().getType());
1785 Type lowIndexTy = typeConverter->convertType(op.getLowIndex().getType());
1786 Value castInput = typeConverter->materializeTargetConversion(
1787 rewriter, op->getLoc(), inputTy, op.getInput());
1788 Value castLowIndex = typeConverter->materializeTargetConversion(
1789 rewriter, op->getLoc(), lowIndexTy, op.getLowIndex());
1791 auto sigDetail =
getSignalDetail(rewriter, &getDialect(), op->getLoc(),
1795 sigDetail[0], castLowIndex);
1796 rewriter.replaceOp(op,
createSubSig(&getDialect(), rewriter, op->getLoc(),
1797 sigDetail, adjustedPtr, sigDetail[1]));
1805 struct SigExtractOpConversion
1806 :
public ConvertOpToLLVMPattern<llhd::SigExtractOp> {
1807 using ConvertOpToLLVMPattern<llhd::SigExtractOp>::ConvertOpToLLVMPattern;
1810 matchAndRewrite(llhd::SigExtractOp op, OpAdaptor adaptor,
1811 ConversionPatternRewriter &rewriter)
const override {
1813 Type inputTy = typeConverter->convertType(op.getInput().getType());
1814 Type lowBitTy = typeConverter->convertType(op.getLowBit().getType());
1815 Value castInput = typeConverter->materializeTargetConversion(
1816 rewriter, op->getLoc(), inputTy, op.getInput());
1817 Value castLowBit = typeConverter->materializeTargetConversion(
1818 rewriter, op->getLoc(), lowBitTy, op.getLowBit());
1820 auto sigDetail =
getSignalDetail(rewriter, &getDialect(), op->getLoc(),
1824 rewriter.getI64Type(), castLowBit);
1826 auto adjustedStart =
1827 rewriter.create<LLVM::AddOp>(op->getLoc(), sigDetail[1], zextStart);
1830 op->getLoc(), &getDialect(), rewriter, sigDetail[0], adjustedStart);
1832 rewriter.replaceOp(op,
createSubSig(&getDialect(), rewriter, op->getLoc(),
1833 sigDetail, adjusted.first,
1842 struct SigStructExtractOpConversion
1843 :
public ConvertOpToLLVMPattern<llhd::SigStructExtractOp> {
1844 using ConvertOpToLLVMPattern<
1845 llhd::SigStructExtractOp>::ConvertOpToLLVMPattern;
1848 matchAndRewrite(llhd::SigStructExtractOp op, OpAdaptor adaptor,
1849 ConversionPatternRewriter &rewriter)
const override {
1851 Type llvmStructTy = typeConverter->convertType(op.getStructType());
1852 Type inputTy = typeConverter->convertType(op.getInput().getType());
1853 Value castInput = typeConverter->materializeTargetConversion(
1854 rewriter, op->getLoc(), inputTy, op.getInput());
1856 std::vector<Value> sigDetail =
1860 uint32_t index = HWToLLVMEndianessConverter::llvmIndexOfStructField(
1861 op.getStructType(), op.getField());
1863 auto indexC = rewriter.create<LLVM::ConstantOp>(
1864 op->getLoc(), rewriter.getI32Type(), rewriter.getI32IntegerAttr(index));
1867 llvmStructTy.cast<LLVM::LLVMStructType>().getBody()[index]);
1869 op->getLoc(), rewriter, llvmStructTy, elemPtrTy, sigDetail[0], indexC);
1871 rewriter.replaceOp(op,
createSubSig(&getDialect(), rewriter, op->getLoc(),
1872 sigDetail, adjusted, sigDetail[1]));
1881 struct SigArrayGetOpConversion
1882 :
public ConvertOpToLLVMPattern<llhd::SigArrayGetOp> {
1883 using ConvertOpToLLVMPattern<llhd::SigArrayGetOp>::ConvertOpToLLVMPattern;
1886 matchAndRewrite(llhd::SigArrayGetOp op, OpAdaptor adaptor,
1887 ConversionPatternRewriter &rewriter)
const override {
1889 auto llvmArrTy = typeConverter->convertType(op.getArrayType());
1890 Type inputTy = typeConverter->convertType(op.getInput().getType());
1891 Type indexTy = typeConverter->convertType(op.getIndex().getType());
1892 Value castInput = typeConverter->materializeTargetConversion(
1893 rewriter, op->getLoc(), inputTy, op.getInput());
1894 Value castIndex = typeConverter->materializeTargetConversion(
1895 rewriter, op->getLoc(), indexTy, op.getIndex());
1897 auto sigDetail =
getSignalDetail(rewriter, &getDialect(), op->getLoc(),
1901 sigDetail[0], castIndex);
1902 rewriter.replaceOp(op,
createSubSig(&getDialect(), rewriter, op->getLoc(),
1903 sigDetail, adjustedPtr, sigDetail[1]));
1917 struct VarOpConversion : ConvertToLLVMPattern {
1918 explicit VarOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter)
1919 : ConvertToLLVMPattern(VarOp::getOperationName(), ctx, typeConverter) {}
1922 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
1923 ConversionPatternRewriter &rewriter)
const override {
1924 VarOpAdaptor transformed(operands);
1927 Type initTy = typeConverter->convertType(transformed.getInit().getType());
1929 auto oneC = rewriter.create<LLVM::ConstantOp>(
1930 op->getLoc(), i32Ty, rewriter.getI32IntegerAttr(1));
1931 auto alloca = rewriter.create<LLVM::AllocaOp>(
1933 rewriter.create<LLVM::StoreOp>(op->getLoc(), transformed.getInit(), alloca);
1934 rewriter.replaceOp(op, alloca.getResult());
1943 struct StoreOpConversion : ConvertToLLVMPattern {
1944 explicit StoreOpConversion(MLIRContext *ctx, LLVMTypeConverter &typeConverter)
1945 : ConvertToLLVMPattern(llhd::StoreOp::getOperationName(), ctx,
1949 matchAndRewrite(Operation *op, ArrayRef<Value> operands,
1950 ConversionPatternRewriter &rewriter)
const override {
1951 llhd::StoreOpAdaptor transformed(operands);
1953 rewriter.replaceOpWithNewOp<LLVM::StoreOp>(op, transformed.getValue(),
1954 transformed.getPointer());
1962 OneToOneConvertToLLVMPattern<llhd::LoadOp, LLVM::LoadOp>;
1969 struct LLHDToLLVMLoweringPass
1970 :
public ConvertLLHDToLLVMBase<LLHDToLLVMLoweringPass> {
1971 void runOnOperation()
override;
1978 size_t ®Counter) {
1979 MLIRContext *ctx = converter.getDialect()->getContext();
1982 patterns.add<ConstantTimeOpConversion>(ctx, converter);
1985 patterns.add<SigExtractOpConversion, SigArraySliceOpConversion,
1986 SigArrayGetOpConversion, SigStructExtractOpConversion>(
1990 patterns.add<ProcOpConversion, WaitOpConversion, HaltOpConversion>(ctx,
1992 patterns.add<EntityOpConversion>(ctx, converter, sigCounter, regCounter);
1995 patterns.add<PrbOpConversion, DrvOpConversion>(ctx, converter);
1996 patterns.add<SigOpConversion>(ctx, converter, sigCounter);
1997 patterns.add<RegOpConversion>(ctx, converter, regCounter);
2000 patterns.add<VarOpConversion, StoreOpConversion>(ctx, converter);
2005 converter.addConversion(
2007 converter.addConversion(
2009 converter.addConversion(
2013 void LLHDToLLVMLoweringPass::runOnOperation() {
2020 size_t sigCounter = 0;
2023 size_t regCounter = 0;
2025 RewritePatternSet
patterns(&getContext());
2026 auto converter = mlir::LLVMTypeConverter(&getContext());
2034 patterns.add<InstOpConversion>(&getContext(), converter);
2036 LLVMConversionTarget target(getContext());
2037 target.addIllegalOp<InstOp>();
2038 target.addLegalOp<UnrealizedConversionCastOp>();
2039 cf::populateControlFlowToLLVMConversionPatterns(converter,
patterns);
2040 arith::populateArithToLLVMConversionPatterns(converter,
patterns);
2044 applyPartialConversion(getOperation(), target, std::move(
patterns))))
2045 signalPassFailure();
2049 populateFuncToLLVMConversionPatterns(converter,
patterns);
2054 DenseMap<std::pair<Type, ArrayAttr>, LLVM::GlobalOp> constAggregateGlobalsMap;
2056 constAggregateGlobalsMap);
2059 arith::populateArithToLLVMConversionPatterns(converter,
patterns);
2061 target.addLegalDialect<LLVM::LLVMDialect>();
2062 target.addLegalOp<ModuleOp>();
2065 if (failed(applyFullConversion(getOperation(), target, std::move(
patterns))))
2066 signalPassFailure();
2070 mlir::populateReconcileUnrealizedCastsPatterns(
patterns);
2071 target.addIllegalOp<UnrealizedConversionCastOp>();
2074 if (failed(applyFullConversion(getOperation(), target, std::move(
patterns))))
2075 signalPassFailure();
2080 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 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 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 Value shiftArraySigPointer(Location loc, ConversionPatternRewriter &rewriter, Type arrTy, Value pointer, Value index)
Shift the pointer of an array-typed signal, to change its view as if the desired slice/element was ex...
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 Type unwrapLLVMPtr(Type ty)
Unwrap the given LLVM pointer type, returning its element value.
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)
static Value shiftStructuredSigPointer(Location loc, ConversionPatternRewriter &rewriter, Type structTy, Type elemPtrTy, Value pointer, Value index)
Shift the pointer of a structured-type (array or struct) signal, to change its view as if the desired...
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 gepPersistenceState(LLVM::LLVMDialect *dialect, Location loc, ConversionPatternRewriter &rewriter, Type elementTy, int index, Value state)
Insert a GEP operation to the pointer of the i-th value in the process persistence table.
static Value createSubSig(LLVM::LLVMDialect *dialect, ConversionPatternRewriter &rewriter, Location loc, std::vector< Value > originDetail, Value newPtr, Value newOffset)
Create a subsignal struct.
static int64_t size(hw::ArrayType mType, capnp::schema::Field::Reader cField)
Returns the expected size of an array (capnp list) in 64-bit words.
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.