21#include "mlir/Conversion/ArithToLLVM/ArithToLLVM.h"
22#include "mlir/Conversion/ControlFlowToLLVM/ControlFlowToLLVM.h"
23#include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVM.h"
24#include "mlir/Conversion/IndexToLLVM/IndexToLLVM.h"
25#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
26#include "mlir/Conversion/LLVMCommon/TypeConverter.h"
27#include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h"
28#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
29#include "mlir/Dialect/Func/IR/FuncOps.h"
30#include "mlir/Dialect/Index/IR/IndexOps.h"
31#include "mlir/Dialect/LLVMIR/FunctionCallUtils.h"
32#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
33#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
34#include "mlir/Dialect/SCF/IR/SCF.h"
35#include "mlir/IR/BuiltinDialect.h"
36#include "mlir/Pass/Pass.h"
37#include "mlir/Transforms/DialectConversion.h"
38#include "llvm/Support/Debug.h"
39#include "llvm/Support/FormatVariadic.h"
43#define DEBUG_TYPE "lower-arc-to-llvm"
46#define GEN_PASS_DEF_LOWERARCTOLLVM
47#include "circt/Conversion/Passes.h.inc"
60 return modelName +
"_eval";
66 using OpConversionPattern::OpConversionPattern;
68 matchAndRewrite(arc::ModelOp op, OpAdaptor adaptor,
69 ConversionPatternRewriter &rewriter)
const final {
71 IRRewriter::InsertionGuard guard(rewriter);
72 rewriter.setInsertionPointToEnd(&op.getBodyBlock());
73 func::ReturnOp::create(rewriter, op.getLoc());
78 rewriter.getFunctionType(op.getBody().getArgumentTypes(), {});
80 mlir::func::FuncOp::create(rewriter, op.getLoc(), funcName, funcType);
81 rewriter.inlineRegionBefore(op.getRegion(), func.getBody(), func.end());
87struct AllocStorageOpLowering
89 using OpConversionPattern::OpConversionPattern;
91 matchAndRewrite(arc::AllocStorageOp op, OpAdaptor adaptor,
92 ConversionPatternRewriter &rewriter)
const final {
93 auto type = typeConverter->convertType(op.getType());
94 if (!op.getOffset().has_value())
96 rewriter.replaceOpWithNewOp<LLVM::GEPOp>(op, type, rewriter.getI8Type(),
98 LLVM::GEPArg(*op.getOffset()));
103template <
class ConcreteOp>
107 using OpAdaptor =
typename ConcreteOp::Adaptor;
110 matchAndRewrite(ConcreteOp op, OpAdaptor adaptor,
111 ConversionPatternRewriter &rewriter)
const final {
113 auto offsetAttr = op->template getAttrOfType<IntegerAttr>(
"offset");
116 Value ptr = LLVM::GEPOp::create(
117 rewriter, op->getLoc(), adaptor.getStorage().getType(),
118 rewriter.getI8Type(), adaptor.getStorage(),
119 LLVM::GEPArg(offsetAttr.getValue().getZExtValue()));
120 rewriter.replaceOp(op, ptr);
126 using OpConversionPattern::OpConversionPattern;
128 matchAndRewrite(arc::StateReadOp op, OpAdaptor adaptor,
129 ConversionPatternRewriter &rewriter)
const final {
130 auto type = typeConverter->convertType(op.getType());
131 rewriter.replaceOpWithNewOp<LLVM::LoadOp>(op, type, adaptor.getState());
137 using OpConversionPattern::OpConversionPattern;
139 matchAndRewrite(arc::StateWriteOp op, OpAdaptor adaptor,
140 ConversionPatternRewriter &rewriter)
const final {
141 if (adaptor.getCondition()) {
142 rewriter.replaceOpWithNewOp<scf::IfOp>(
143 op, adaptor.getCondition(), [&](
auto &builder,
auto loc) {
144 LLVM::StoreOp::create(builder, loc, adaptor.getValue(),
146 scf::YieldOp::create(builder, loc);
149 rewriter.replaceOpWithNewOp<LLVM::StoreOp>(op, adaptor.getValue(),
157 using OpConversionPattern::OpConversionPattern;
159 matchAndRewrite(arc::AllocMemoryOp op, OpAdaptor adaptor,
160 ConversionPatternRewriter &rewriter)
const final {
161 auto offsetAttr = op->getAttrOfType<IntegerAttr>(
"offset");
164 Value ptr = LLVM::GEPOp::create(
165 rewriter, op.getLoc(), adaptor.getStorage().getType(),
166 rewriter.getI8Type(), adaptor.getStorage(),
167 LLVM::GEPArg(offsetAttr.getValue().getZExtValue()));
169 rewriter.replaceOp(op, ptr);
175 using OpConversionPattern::OpConversionPattern;
177 matchAndRewrite(arc::StorageGetOp op, OpAdaptor adaptor,
178 ConversionPatternRewriter &rewriter)
const final {
179 Value offset = LLVM::ConstantOp::create(
180 rewriter, op.getLoc(), rewriter.getI32Type(), op.getOffsetAttr());
181 Value ptr = LLVM::GEPOp::create(
182 rewriter, op.getLoc(), adaptor.getStorage().getType(),
183 rewriter.getI8Type(), adaptor.getStorage(), offset);
184 rewriter.replaceOp(op, ptr);
194static MemoryAccess prepareMemoryAccess(Location loc, Value memory,
195 Value address, MemoryType type,
196 ConversionPatternRewriter &rewriter) {
197 auto zextAddrType = rewriter.getIntegerType(
198 cast<IntegerType>(address.getType()).getWidth() + 1);
199 Value
addr = LLVM::ZExtOp::create(rewriter, loc, zextAddrType, address);
201 LLVM::ConstantOp::create(rewriter, loc, zextAddrType,
202 rewriter.getI32IntegerAttr(type.getNumWords()));
203 Value withinBounds = LLVM::ICmpOp::create(
204 rewriter, loc, LLVM::ICmpPredicate::ult, addr, addrLimit);
205 Value ptr = LLVM::GEPOp::create(
206 rewriter, loc, LLVM::LLVMPointerType::get(memory.getContext()),
207 rewriter.getIntegerType(type.getStride() * 8), memory, ValueRange{addr});
208 return {ptr, withinBounds};
212 using OpConversionPattern::OpConversionPattern;
214 matchAndRewrite(arc::MemoryReadOp op, OpAdaptor adaptor,
215 ConversionPatternRewriter &rewriter)
const final {
216 auto type = typeConverter->convertType(op.getType());
217 auto memoryType = cast<MemoryType>(op.getMemory().getType());
219 prepareMemoryAccess(op.getLoc(), adaptor.getMemory(),
220 adaptor.getAddress(), memoryType, rewriter);
224 rewriter.replaceOpWithNewOp<scf::IfOp>(
225 op, access.withinBounds,
226 [&](
auto &builder,
auto loc) {
227 Value loadOp = LLVM::LoadOp::create(
228 builder, loc, memoryType.getWordType(), access.ptr);
229 scf::YieldOp::create(builder, loc, loadOp);
231 [&](
auto &builder,
auto loc) {
232 Value zeroValue = LLVM::ConstantOp::create(
233 builder, loc, type, builder.getI64IntegerAttr(0));
234 scf::YieldOp::create(builder, loc, zeroValue);
241 using OpConversionPattern::OpConversionPattern;
243 matchAndRewrite(arc::MemoryWriteOp op, OpAdaptor adaptor,
244 ConversionPatternRewriter &rewriter)
const final {
245 auto access = prepareMemoryAccess(
246 op.getLoc(), adaptor.getMemory(), adaptor.getAddress(),
247 cast<MemoryType>(op.getMemory().getType()), rewriter);
248 auto enable = access.withinBounds;
249 if (adaptor.getEnable())
250 enable = LLVM::AndOp::create(rewriter, op.getLoc(), adaptor.getEnable(),
254 rewriter.replaceOpWithNewOp<scf::IfOp>(
255 op, enable, [&](
auto &builder,
auto loc) {
256 LLVM::StoreOp::create(builder, loc, adaptor.getData(), access.ptr);
257 scf::YieldOp::create(builder, loc);
265 using OpConversionPattern::OpConversionPattern;
267 matchAndRewrite(seq::ClockGateOp op, OpAdaptor adaptor,
268 ConversionPatternRewriter &rewriter)
const final {
269 rewriter.replaceOpWithNewOp<LLVM::AndOp>(op, adaptor.getInput(),
270 adaptor.getEnable());
277 using OpConversionPattern::OpConversionPattern;
279 matchAndRewrite(seq::ClockInverterOp op, OpAdaptor adaptor,
280 ConversionPatternRewriter &rewriter)
const final {
281 auto constTrue = LLVM::ConstantOp::create(rewriter, op->getLoc(),
282 rewriter.getI1Type(), 1);
283 rewriter.replaceOpWithNewOp<LLVM::XOrOp>(op, adaptor.getInput(), constTrue);
289 using OpConversionPattern::OpConversionPattern;
291 matchAndRewrite(arc::ZeroCountOp op, OpAdaptor adaptor,
292 ConversionPatternRewriter &rewriter)
const override {
294 IntegerAttr isZeroPoison = rewriter.getBoolAttr(
true);
296 if (op.getPredicate() == arc::ZeroCountPredicate::leading) {
297 rewriter.replaceOpWithNewOp<LLVM::CountLeadingZerosOp>(
298 op, adaptor.getInput().getType(), adaptor.getInput(), isZeroPoison);
302 rewriter.replaceOpWithNewOp<LLVM::CountTrailingZerosOp>(
303 op, adaptor.getInput().getType(), adaptor.getInput(), isZeroPoison);
309 using OpConversionPattern::OpConversionPattern;
311 matchAndRewrite(seq::ConstClockOp op, OpAdaptor adaptor,
312 ConversionPatternRewriter &rewriter)
const override {
313 rewriter.replaceOpWithNewOp<LLVM::ConstantOp>(
314 op, rewriter.getI1Type(),
static_cast<int64_t
>(op.getValue()));
319template <
typename OpTy>
322 using OpAdaptor =
typename OpTy::Adaptor;
324 matchAndRewrite(OpTy op, OpAdaptor adaptor,
325 ConversionPatternRewriter &rewriter)
const override {
326 rewriter.replaceOp(op, adaptor.getInput());
340 size_t numStateBytes;
341 llvm::DenseMap<StringRef, StateInfo> states;
342 mlir::FlatSymbolRefAttr initialFnSymbol;
343 mlir::FlatSymbolRefAttr finalFnSymbol;
346template <
typename OpTy>
348 ModelAwarePattern(
const TypeConverter &typeConverter, MLIRContext *
context,
349 llvm::DenseMap<StringRef, ModelInfoMap> &modelInfo)
351 modelInfo(modelInfo) {}
354 Value createPtrToPortState(ConversionPatternRewriter &rewriter, Location loc,
355 Value state,
const StateInfo &port)
const {
356 MLIRContext *ctx = rewriter.getContext();
357 return LLVM::GEPOp::create(rewriter, loc, LLVM::LLVMPointerType::get(ctx),
358 IntegerType::get(ctx, 8), state,
359 LLVM::GEPArg(port.offset));
362 llvm::DenseMap<StringRef, ModelInfoMap> &modelInfo;
367struct SimInstantiateOpLowering
368 :
public ModelAwarePattern<arc::SimInstantiateOp> {
369 using ModelAwarePattern::ModelAwarePattern;
372 matchAndRewrite(arc::SimInstantiateOp op, OpAdaptor adaptor,
373 ConversionPatternRewriter &rewriter)
const final {
374 auto modelIt = modelInfo.find(
375 cast<SimModelInstanceType>(op.getBody().getArgument(0).getType())
378 ModelInfoMap &model = modelIt->second;
380 bool useRuntime = op.getRuntimeModel().has_value();
382 ModuleOp moduleOp = op->getParentOfType<ModuleOp>();
386 ConversionPatternRewriter::InsertionGuard guard(rewriter);
390 Type convertedIndex = typeConverter->convertType(rewriter.getIndexType());
391 Location loc = op.getLoc();
396 auto ptrTy = LLVM::LLVMPointerType::get(getContext());
400 if (op.getRuntimeArgs().has_value()) {
401 SmallVector<int8_t> argStringVec(op.getRuntimeArgsAttr().begin(),
402 op.getRuntimeArgsAttr().end());
403 argStringVec.push_back(
'\0');
404 auto strAttr = mlir::DenseElementsAttr::get(
405 mlir::RankedTensorType::get({(int64_t)argStringVec.size()},
406 rewriter.getI8Type()),
407 llvm::ArrayRef(argStringVec));
409 auto arrayCst = LLVM::ConstantOp::create(
411 LLVM::LLVMArrayType::get(rewriter.getI8Type(), argStringVec.size()),
413 auto cst1 = LLVM::ConstantOp::create(rewriter, loc,
414 rewriter.getI32IntegerAttr(1));
415 runtimeArgs = LLVM::AllocaOp::create(rewriter, loc, ptrTy,
416 arrayCst.getType(), cst1);
417 LLVM::LifetimeStartOp::create(rewriter, loc, runtimeArgs);
418 LLVM::StoreOp::create(rewriter, loc, arrayCst, runtimeArgs);
420 runtimeArgs = LLVM::ZeroOp::create(rewriter, loc, ptrTy).getResult();
423 auto rtModelPtr = LLVM::AddressOfOp::create(rewriter, loc, ptrTy,
424 op.getRuntimeModelAttr())
427 LLVM::CallOp::create(rewriter, loc, {ptrTy},
428 runtime::APICallbacks::symNameAllocInstance,
429 {rtModelPtr, runtimeArgs})
432 if (op.getRuntimeArgs().has_value())
433 LLVM::LifetimeEndOp::create(rewriter, loc, runtimeArgs);
437 FailureOr<LLVM::LLVMFuncOp> mallocFunc =
438 LLVM::lookupOrCreateMallocFn(rewriter, moduleOp, convertedIndex);
439 if (failed(mallocFunc))
442 Value numStateBytes = LLVM::ConstantOp::create(
443 rewriter, loc, convertedIndex, model.numStateBytes);
444 allocated = LLVM::CallOp::create(rewriter, loc, mallocFunc.value(),
445 ValueRange{numStateBytes})
448 LLVM::ConstantOp::create(rewriter, loc, rewriter.getI8Type(), 0);
449 LLVM::MemsetOp::create(rewriter, loc, allocated, zero, numStateBytes,
454 if (model.initialFnSymbol) {
455 auto initialFnType = LLVM::LLVMFunctionType::get(
456 LLVM::LLVMVoidType::get(op.getContext()),
457 {LLVM::LLVMPointerType::get(op.getContext())});
458 LLVM::CallOp::create(rewriter, loc, initialFnType, model.initialFnSymbol,
459 ValueRange{allocated});
463 rewriter.inlineBlockBefore(&adaptor.getBody().getBlocks().front(), op,
467 if (model.finalFnSymbol) {
468 auto finalFnType = LLVM::LLVMFunctionType::get(
469 LLVM::LLVMVoidType::get(op.getContext()),
470 {LLVM::LLVMPointerType::get(op.getContext())});
471 LLVM::CallOp::create(rewriter, loc, finalFnType, model.finalFnSymbol,
472 ValueRange{allocated});
476 LLVM::CallOp::create(rewriter, loc, TypeRange{},
477 runtime::APICallbacks::symNameDeleteInstance,
480 FailureOr<LLVM::LLVMFuncOp> freeFunc =
481 LLVM::lookupOrCreateFreeFn(rewriter, moduleOp);
482 if (failed(freeFunc))
485 LLVM::CallOp::create(rewriter, loc, freeFunc.value(),
486 ValueRange{allocated});
489 rewriter.eraseOp(op);
494struct SimSetInputOpLowering :
public ModelAwarePattern<arc::SimSetInputOp> {
495 using ModelAwarePattern::ModelAwarePattern;
498 matchAndRewrite(arc::SimSetInputOp op, OpAdaptor adaptor,
499 ConversionPatternRewriter &rewriter)
const final {
501 modelInfo.find(cast<SimModelInstanceType>(op.getInstance().getType())
504 ModelInfoMap &model = modelIt->second;
506 auto portIt = model.states.find(op.getInput());
507 if (portIt == model.states.end()) {
510 rewriter.eraseOp(op);
514 StateInfo &port = portIt->second;
515 Value statePtr = createPtrToPortState(rewriter, op.getLoc(),
516 adaptor.getInstance(), port);
517 rewriter.replaceOpWithNewOp<LLVM::StoreOp>(op, adaptor.getValue(),
524struct SimGetPortOpLowering :
public ModelAwarePattern<arc::SimGetPortOp> {
525 using ModelAwarePattern::ModelAwarePattern;
528 matchAndRewrite(arc::SimGetPortOp op, OpAdaptor adaptor,
529 ConversionPatternRewriter &rewriter)
const final {
531 modelInfo.find(cast<SimModelInstanceType>(op.getInstance().getType())
534 ModelInfoMap &model = modelIt->second;
536 auto type = typeConverter->convertType(op.getValue().getType());
539 auto portIt = model.states.find(op.getPort());
540 if (portIt == model.states.end()) {
543 rewriter.replaceOpWithNewOp<LLVM::ConstantOp>(op, type, 0);
547 StateInfo &port = portIt->second;
548 Value statePtr = createPtrToPortState(rewriter, op.getLoc(),
549 adaptor.getInstance(), port);
550 rewriter.replaceOpWithNewOp<LLVM::LoadOp>(op, type, statePtr);
556struct SimStepOpLowering :
public ModelAwarePattern<arc::SimStepOp> {
557 using ModelAwarePattern::ModelAwarePattern;
560 matchAndRewrite(arc::SimStepOp op, OpAdaptor adaptor,
561 ConversionPatternRewriter &rewriter)
const final {
562 StringRef modelName = cast<SimModelInstanceType>(op.getInstance().getType())
566 StringAttr evalFunc =
568 rewriter.replaceOpWithNewOp<LLVM::CallOp>(op, mlir::TypeRange(), evalFunc,
569 adaptor.getInstance());
578struct SimEmitValueOpLowering
580 using OpConversionPattern::OpConversionPattern;
583 matchAndRewrite(arc::SimEmitValueOp op, OpAdaptor adaptor,
584 ConversionPatternRewriter &rewriter)
const final {
585 auto valueType = dyn_cast<IntegerType>(adaptor.getValue().getType());
589 Location loc = op.getLoc();
591 ModuleOp moduleOp = op->getParentOfType<ModuleOp>();
595 SmallVector<Value> printfVariadicArgs;
596 SmallString<16> printfFormatStr;
597 int remainingBits = valueType.getWidth();
598 Value value = adaptor.getValue();
602 constexpr llvm::StringRef intFormatter =
"llx";
603 auto intType = IntegerType::get(getContext(), 64);
604 Value shiftValue = LLVM::ConstantOp::create(
605 rewriter, loc, rewriter.getIntegerAttr(valueType, intType.getWidth()));
607 if (valueType.getWidth() < intType.getWidth()) {
608 int width = llvm::divideCeil(valueType.getWidth(), 4);
609 printfFormatStr = llvm::formatv(
"%0{0}{1}", width, intFormatter);
610 printfVariadicArgs.push_back(
611 LLVM::ZExtOp::create(rewriter, loc, intType, value));
616 int otherChunkWidth = intType.getWidth() / 4;
617 int firstChunkWidth =
618 llvm::divideCeil(valueType.getWidth() % intType.getWidth(), 4);
619 if (firstChunkWidth == 0) {
620 firstChunkWidth = otherChunkWidth;
623 std::string firstChunkFormat =
624 llvm::formatv(
"%0{0}{1}", firstChunkWidth, intFormatter);
625 std::string otherChunkFormat =
626 llvm::formatv(
"%0{0}{1}", otherChunkWidth, intFormatter);
628 for (
int i = 0; remainingBits > 0; ++i) {
631 printfVariadicArgs.push_back(
632 LLVM::TruncOp::create(rewriter, loc, intType, value));
635 printfFormatStr.append(i == 0 ? firstChunkFormat : otherChunkFormat);
638 LLVM::LShrOp::create(rewriter, loc, value, shiftValue).getResult();
639 remainingBits -= intType.getWidth();
644 auto printfFunc = LLVM::lookupOrCreateFn(
645 rewriter, moduleOp,
"printf", LLVM::LLVMPointerType::get(getContext()),
646 LLVM::LLVMVoidType::get(getContext()),
true);
647 if (failed(printfFunc))
651 SmallString<16> formatStrName{
"_arc_sim_emit_"};
652 formatStrName.append(adaptor.getValueName());
653 LLVM::GlobalOp formatStrGlobal;
654 if (!(formatStrGlobal =
655 moduleOp.lookupSymbol<LLVM::GlobalOp>(formatStrName))) {
656 ConversionPatternRewriter::InsertionGuard insertGuard(rewriter);
658 SmallString<16> formatStr = adaptor.getValueName();
659 formatStr.append(
" = ");
660 formatStr.append(printfFormatStr);
661 formatStr.append(
"\n");
662 SmallVector<char> formatStrVec{formatStr.begin(), formatStr.end()};
663 formatStrVec.push_back(0);
665 rewriter.setInsertionPointToStart(moduleOp.getBody());
667 LLVM::LLVMArrayType::get(rewriter.getI8Type(), formatStrVec.size());
668 formatStrGlobal = LLVM::GlobalOp::create(
669 rewriter, loc, globalType,
true,
670 LLVM::Linkage::Internal,
671 formatStrName, rewriter.getStringAttr(formatStrVec),
675 Value formatStrGlobalPtr =
676 LLVM::AddressOfOp::create(rewriter, loc, formatStrGlobal);
680 printfVariadicArgs.push_back(formatStrGlobalPtr);
681 std::reverse(printfVariadicArgs.begin(), printfVariadicArgs.end());
683 rewriter.replaceOpWithNewOp<LLVM::CallOp>(op, printfFunc.value(),
692static LogicalResult
convert(arc::ExecuteOp op, arc::ExecuteOp::Adaptor adaptor,
693 ConversionPatternRewriter &rewriter,
694 const TypeConverter &converter) {
696 if (failed(rewriter.convertRegionTypes(&op.getBody(), converter)))
702 auto *blockBefore = rewriter.getInsertionBlock();
704 rewriter.splitBlock(blockBefore, rewriter.getInsertionPoint());
707 rewriter.setInsertionPointToEnd(blockBefore);
708 mlir::cf::BranchOp::create(rewriter, op.getLoc(), &op.getBody().front(),
709 adaptor.getInputs());
713 for (
auto &block : op.getBody()) {
714 auto outputOp = dyn_cast<arc::OutputOp>(block.getTerminator());
717 rewriter.setInsertionPointToEnd(&block);
718 rewriter.replaceOpWithNewOp<mlir::cf::BranchOp>(outputOp, blockAfter,
719 outputOp.getOperands());
723 rewriter.inlineRegionBefore(op.getBody(), blockAfter);
727 SmallVector<Value> args;
728 args.reserve(op.getNumResults());
729 for (
auto result : op.getResults())
730 args.push_back(blockAfter->addArgument(result.getType(), result.getLoc()));
731 rewriter.replaceOp(op, args);
732 auto conversion = converter.convertBlockSignature(blockAfter);
735 rewriter.applySignatureConversion(blockAfter, *conversion, &converter);
745 using OpConversionPattern::OpConversionPattern;
752 ConversionPatternRewriter &rewriter)
const final {
754 auto modelInfoStructType = LLVM::LLVMStructType::getLiteral(
755 getContext(), {rewriter.getI64Type(), rewriter.getI64Type(),
756 LLVM::LLVMPointerType::get(getContext())});
758 "Unexpected size of ArcRuntimeModelInfo struct");
761 rewriter.setInsertionPoint(op);
762 SmallVector<char, 16> modNameArray(op.getName().begin(),
764 modNameArray.push_back(
'\0');
765 auto nameGlobalType =
766 LLVM::LLVMArrayType::get(rewriter.getI8Type(), modNameArray.size());
767 SmallString<16> globalSymName{
"_arc_mod_name_"};
768 globalSymName.append(op.getName());
769 auto nameGlobal = LLVM::GlobalOp::create(
770 rewriter, op.getLoc(), nameGlobalType,
true,
771 LLVM::Linkage::Internal,
772 globalSymName, rewriter.getStringAttr(modNameArray),
779 auto modInfoGlobalOp =
780 LLVM::GlobalOp::create(rewriter, op.getLoc(), modelInfoStructType,
781 false, LLVM::Linkage::External,
782 op.getSymName(), Attribute{});
785 Region &initRegion = modInfoGlobalOp.getInitializerRegion();
786 Block *initBlock = rewriter.createBlock(&initRegion);
787 rewriter.setInsertionPointToStart(initBlock);
788 auto apiVersionCst = LLVM::ConstantOp::create(
790 auto numStateBytesCst = LLVM::ConstantOp::create(rewriter, op.getLoc(),
791 op.getNumStateBytesAttr());
793 LLVM::AddressOfOp::create(rewriter, op.getLoc(), nameGlobal);
795 LLVM::PoisonOp::create(rewriter, op.getLoc(), modelInfoStructType);
798 initStruct = LLVM::InsertValueOp::create(
799 rewriter, op.getLoc(), initStruct, apiVersionCst, ArrayRef<int64_t>{0});
801 "Unexpected offset of field apiVersion");
804 LLVM::InsertValueOp::create(rewriter, op.getLoc(), initStruct,
805 numStateBytesCst, ArrayRef<int64_t>{1});
807 "Unexpected offset of field numStateBytes");
809 initStruct = LLVM::InsertValueOp::create(rewriter, op.getLoc(), initStruct,
810 nameAddr, ArrayRef<int64_t>{2});
812 "Unexpected offset of field modelName");
814 LLVM::ReturnOp::create(rewriter, op.getLoc(), initStruct);
816 rewriter.replaceOp(op, modInfoGlobalOp);
826struct LowerArcToLLVMPass
827 :
public circt::impl::LowerArcToLLVMBase<LowerArcToLLVMPass> {
828 void runOnOperation()
override;
832void LowerArcToLLVMPass::runOnOperation() {
836 DenseMap<Region *, hw::ConstantOp> zeros;
837 getOperation().walk([&](Operation *op) {
838 if (op->hasTrait<OpTrait::ConstantLike>())
840 for (
auto result : op->getResults()) {
841 auto type = dyn_cast<IntegerType>(result.getType());
842 if (!type || type.getWidth() != 0)
844 auto *region = op->getParentRegion();
845 auto &zero = zeros[region];
847 auto builder = OpBuilder::atBlockBegin(®ion->front());
851 result.replaceAllUsesWith(zero);
867 LLVMConversionTarget target(getContext());
868 target.addLegalOp<mlir::ModuleOp>();
869 target.addLegalOp<scf::YieldOp>();
872 LLVMTypeConverter converter(&getContext());
873 converter.addConversion([&](seq::ClockType type) {
874 return IntegerType::get(type.getContext(), 1);
876 converter.addConversion([&](StorageType type) {
877 return LLVM::LLVMPointerType::get(type.getContext());
879 converter.addConversion([&](MemoryType type) {
880 return LLVM::LLVMPointerType::get(type.getContext());
882 converter.addConversion([&](StateType type) {
883 return LLVM::LLVMPointerType::get(type.getContext());
885 converter.addConversion([&](SimModelInstanceType type) {
886 return LLVM::LLVMPointerType::get(type.getContext());
893 populateSCFToControlFlowConversionPatterns(
patterns);
894 populateFuncToLLVMConversionPatterns(converter,
patterns);
895 cf::populateControlFlowToLLVMConversionPatterns(converter,
patterns);
896 arith::populateArithToLLVMConversionPatterns(converter,
patterns);
897 index::populateIndexToLLVMConversionPatterns(converter,
patterns);
898 populateAnyFunctionOpInterfaceTypeConversionPattern(
patterns, converter);
901 DenseMap<std::pair<Type, ArrayAttr>, LLVM::GlobalOp> constAggregateGlobalsMap;
903 std::optional<HWToLLVMArraySpillCache> spillCacheOpt =
906 OpBuilder spillBuilder(getOperation());
907 spillCacheOpt->spillNonHWOps(spillBuilder, converter, getOperation());
910 constAggregateGlobalsMap, spillCacheOpt);
918 AllocMemoryOpLowering,
919 AllocStateLikeOpLowering<arc::AllocStateOp>,
920 AllocStateLikeOpLowering<arc::RootInputOp>,
921 AllocStateLikeOpLowering<arc::RootOutputOp>,
922 AllocStorageOpLowering,
925 MemoryReadOpLowering,
926 MemoryWriteOpLowering,
928 ReplaceOpWithInputPattern<seq::ToClockOp>,
929 ReplaceOpWithInputPattern<seq::FromClockOp>,
931 SeqConstClockLowering,
932 SimEmitValueOpLowering,
934 StateWriteOpLowering,
935 StorageGetOpLowering,
937 >(converter, &getContext());
941 auto &modelInfo = getAnalysis<ModelInfoAnalysis>();
942 llvm::DenseMap<StringRef, ModelInfoMap> modelMap(modelInfo.infoMap.size());
943 for (
auto &[_, modelInfo] : modelInfo.infoMap) {
944 llvm::DenseMap<StringRef, StateInfo> states(modelInfo.states.size());
945 for (StateInfo &stateInfo : modelInfo.states)
946 states.insert({stateInfo.name, stateInfo});
949 ModelInfoMap{modelInfo.numStateBytes, std::move(states),
950 modelInfo.initialFnSym, modelInfo.finalFnSym}});
953 patterns.add<SimInstantiateOpLowering, SimSetInputOpLowering,
954 SimGetPortOpLowering, SimStepOpLowering>(
955 converter, &getContext(), modelMap);
958 ConversionConfig config;
959 config.allowPatternRollback =
false;
960 if (failed(applyFullConversion(getOperation(), target, std::move(
patterns),
966 return std::make_unique<LowerArcToLLVMPass>();
static std::unique_ptr< Context > context
static llvm::Twine evalSymbolFromModelName(StringRef modelName)
static LogicalResult convert(arc::ExecuteOp op, arc::ExecuteOp::Adaptor adaptor, ConversionPatternRewriter &rewriter, const TypeConverter &converter)
Extension of RewritePatternSet that allows adding matchAndRewrite functions with op adaptors and Conv...
A namespace that is used to store existing names and generate new names in some scope within the IR.
void add(mlir::ModuleOp module)
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...
#define ARC_RUNTIME_API_VERSION
Version of the combined public and internal API.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
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 populateHWToLLVMConversionPatterns(mlir::LLVMTypeConverter &converter, RewritePatternSet &patterns, Namespace &globals, DenseMap< std::pair< Type, ArrayAttr >, mlir::LLVM::GlobalOp > &constAggregateGlobalsMap, std::optional< HWToLLVMArraySpillCache > &spillCacheOpt)
Get the HW to LLVM conversion patterns.
std::unique_ptr< OperationPass< ModuleOp > > createLowerArcToLLVMPass()
Static information for a compiled hardware model, generated by the MLIR lowering.
static constexpr uint64_t runtimeApiVersion
LogicalResult matchAndRewrite(arc::RuntimeModelOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const final
Helper class mapping array values (HW or LLVM Dialect) to pointers to buffers containing the array va...