27#include "mlir/Conversion/ArithToLLVM/ArithToLLVM.h"
28#include "mlir/Conversion/ControlFlowToLLVM/ControlFlowToLLVM.h"
29#include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVM.h"
30#include "mlir/Conversion/IndexToLLVM/IndexToLLVM.h"
31#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
32#include "mlir/Conversion/LLVMCommon/TypeConverter.h"
33#include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h"
34#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
35#include "mlir/Dialect/Func/IR/FuncOps.h"
36#include "mlir/Dialect/Index/IR/IndexOps.h"
37#include "mlir/Dialect/LLVMIR/FunctionCallUtils.h"
38#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
39#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
40#include "mlir/Dialect/SCF/IR/SCF.h"
41#include "mlir/IR/Builders.h"
42#include "mlir/IR/BuiltinDialect.h"
43#include "mlir/Pass/Pass.h"
44#include "mlir/Transforms/DialectConversion.h"
45#include "llvm/Support/Debug.h"
46#include "llvm/Support/FormatVariadic.h"
50#define DEBUG_TYPE "lower-arc-to-llvm"
53#define GEN_PASS_DEF_LOWERARCTOLLVM
54#include "circt/Conversion/Passes.h.inc"
61using namespace runtime;
68 return modelName +
"_eval";
74 using OpConversionPattern::OpConversionPattern;
76 matchAndRewrite(arc::ModelOp op, OpAdaptor adaptor,
77 ConversionPatternRewriter &rewriter)
const final {
79 IRRewriter::InsertionGuard guard(rewriter);
80 rewriter.setInsertionPointToEnd(&op.getBodyBlock());
81 func::ReturnOp::create(rewriter, op.getLoc());
86 rewriter.getFunctionType(op.getBody().getArgumentTypes(), {});
88 mlir::func::FuncOp::create(rewriter, op.getLoc(), funcName, funcType);
89 rewriter.inlineRegionBefore(op.getRegion(), func.getBody(), func.end());
95struct AllocStorageOpLowering
97 using OpConversionPattern::OpConversionPattern;
99 matchAndRewrite(arc::AllocStorageOp op, OpAdaptor adaptor,
100 ConversionPatternRewriter &rewriter)
const final {
101 auto type = typeConverter->convertType(op.getType());
102 if (!op.getOffset().has_value())
104 rewriter.replaceOpWithNewOp<LLVM::GEPOp>(op, type, rewriter.getI8Type(),
106 LLVM::GEPArg(*op.getOffset()));
111template <
class ConcreteOp>
115 using OpAdaptor =
typename ConcreteOp::Adaptor;
118 matchAndRewrite(ConcreteOp op, OpAdaptor adaptor,
119 ConversionPatternRewriter &rewriter)
const final {
121 auto offsetAttr = op->template getAttrOfType<IntegerAttr>(
"offset");
124 Value ptr = LLVM::GEPOp::create(
125 rewriter, op->getLoc(), adaptor.getStorage().getType(),
126 rewriter.getI8Type(), adaptor.getStorage(),
127 LLVM::GEPArg(offsetAttr.getValue().getZExtValue()));
128 rewriter.replaceOp(op, ptr);
134 using OpConversionPattern::OpConversionPattern;
136 matchAndRewrite(arc::StateReadOp op, OpAdaptor adaptor,
137 ConversionPatternRewriter &rewriter)
const final {
138 auto type = typeConverter->convertType(op.getType());
139 rewriter.replaceOpWithNewOp<LLVM::LoadOp>(op, type, adaptor.getState());
145 using OpConversionPattern::OpConversionPattern;
147 matchAndRewrite(arc::StateWriteOp op, OpAdaptor adaptor,
148 ConversionPatternRewriter &rewriter)
const final {
149 if (adaptor.getCondition()) {
150 rewriter.replaceOpWithNewOp<scf::IfOp>(
151 op, adaptor.getCondition(), [&](
auto &builder,
auto loc) {
152 LLVM::StoreOp::create(builder, loc, adaptor.getValue(),
154 scf::YieldOp::create(builder, loc);
157 rewriter.replaceOpWithNewOp<LLVM::StoreOp>(op, adaptor.getValue(),
169 using OpConversionPattern::OpConversionPattern;
171 matchAndRewrite(arc::CurrentTimeOp op, OpAdaptor adaptor,
172 ConversionPatternRewriter &rewriter)
const final {
174 Value ptr = adaptor.getStorage();
175 rewriter.replaceOpWithNewOp<LLVM::LoadOp>(op, rewriter.getI64Type(), ptr);
182 using OpConversionPattern::OpConversionPattern;
184 matchAndRewrite(llhd::IntToTimeOp op, OpAdaptor adaptor,
185 ConversionPatternRewriter &rewriter)
const final {
186 rewriter.replaceOp(op, adaptor.getInput());
193 using OpConversionPattern::OpConversionPattern;
195 matchAndRewrite(llhd::TimeToIntOp op, OpAdaptor adaptor,
196 ConversionPatternRewriter &rewriter)
const final {
197 rewriter.replaceOp(op, adaptor.getInput());
207 using OpConversionPattern::OpConversionPattern;
209 matchAndRewrite(arc::AllocMemoryOp op, OpAdaptor adaptor,
210 ConversionPatternRewriter &rewriter)
const final {
211 auto offsetAttr = op->getAttrOfType<IntegerAttr>(
"offset");
214 Value ptr = LLVM::GEPOp::create(
215 rewriter, op.getLoc(), adaptor.getStorage().getType(),
216 rewriter.getI8Type(), adaptor.getStorage(),
217 LLVM::GEPArg(offsetAttr.getValue().getZExtValue()));
219 rewriter.replaceOp(op, ptr);
225 using OpConversionPattern::OpConversionPattern;
227 matchAndRewrite(arc::StorageGetOp op, OpAdaptor adaptor,
228 ConversionPatternRewriter &rewriter)
const final {
229 Value offset = LLVM::ConstantOp::create(
230 rewriter, op.getLoc(), rewriter.getI32Type(), op.getOffsetAttr());
231 Value ptr = LLVM::GEPOp::create(
232 rewriter, op.getLoc(), adaptor.getStorage().getType(),
233 rewriter.getI8Type(), adaptor.getStorage(), offset);
234 rewriter.replaceOp(op, ptr);
244static MemoryAccess prepareMemoryAccess(Location loc, Value memory,
245 Value address, MemoryType type,
246 ConversionPatternRewriter &rewriter) {
247 auto zextAddrType = rewriter.getIntegerType(
248 cast<IntegerType>(address.getType()).getWidth() + 1);
249 Value
addr = LLVM::ZExtOp::create(rewriter, loc, zextAddrType, address);
251 LLVM::ConstantOp::create(rewriter, loc, zextAddrType,
252 rewriter.getI32IntegerAttr(type.getNumWords()));
253 Value withinBounds = LLVM::ICmpOp::create(
254 rewriter, loc, LLVM::ICmpPredicate::ult, addr, addrLimit);
255 Value ptr = LLVM::GEPOp::create(
256 rewriter, loc, LLVM::LLVMPointerType::get(memory.getContext()),
257 rewriter.getIntegerType(type.getStride() * 8), memory, ValueRange{addr});
258 return {ptr, withinBounds};
262 using OpConversionPattern::OpConversionPattern;
264 matchAndRewrite(arc::MemoryReadOp op, OpAdaptor adaptor,
265 ConversionPatternRewriter &rewriter)
const final {
266 auto type = typeConverter->convertType(op.getType());
267 auto memoryType = cast<MemoryType>(op.getMemory().getType());
269 prepareMemoryAccess(op.getLoc(), adaptor.getMemory(),
270 adaptor.getAddress(), memoryType, rewriter);
274 rewriter.replaceOpWithNewOp<scf::IfOp>(
275 op, access.withinBounds,
276 [&](
auto &builder,
auto loc) {
277 Value loadOp = LLVM::LoadOp::create(
278 builder, loc, memoryType.getWordType(), access.ptr);
279 scf::YieldOp::create(builder, loc, loadOp);
281 [&](
auto &builder,
auto loc) {
282 Value zeroValue = LLVM::ConstantOp::create(
283 builder, loc, type, builder.getI64IntegerAttr(0));
284 scf::YieldOp::create(builder, loc, zeroValue);
291 using OpConversionPattern::OpConversionPattern;
293 matchAndRewrite(arc::MemoryWriteOp op, OpAdaptor adaptor,
294 ConversionPatternRewriter &rewriter)
const final {
295 auto access = prepareMemoryAccess(
296 op.getLoc(), adaptor.getMemory(), adaptor.getAddress(),
297 cast<MemoryType>(op.getMemory().getType()), rewriter);
298 auto enable = access.withinBounds;
299 if (adaptor.getEnable())
300 enable = LLVM::AndOp::create(rewriter, op.getLoc(), adaptor.getEnable(),
304 rewriter.replaceOpWithNewOp<scf::IfOp>(
305 op, enable, [&](
auto &builder,
auto loc) {
306 LLVM::StoreOp::create(builder, loc, adaptor.getData(), access.ptr);
307 scf::YieldOp::create(builder, loc);
315 using OpConversionPattern::OpConversionPattern;
317 matchAndRewrite(seq::ClockGateOp op, OpAdaptor adaptor,
318 ConversionPatternRewriter &rewriter)
const final {
319 rewriter.replaceOpWithNewOp<LLVM::AndOp>(op, adaptor.getInput(),
320 adaptor.getEnable());
327 using OpConversionPattern::OpConversionPattern;
329 matchAndRewrite(seq::ClockInverterOp op, OpAdaptor adaptor,
330 ConversionPatternRewriter &rewriter)
const final {
331 auto constTrue = LLVM::ConstantOp::create(rewriter, op->getLoc(),
332 rewriter.getI1Type(), 1);
333 rewriter.replaceOpWithNewOp<LLVM::XOrOp>(op, adaptor.getInput(), constTrue);
339 using OpConversionPattern::OpConversionPattern;
341 matchAndRewrite(arc::ZeroCountOp op, OpAdaptor adaptor,
342 ConversionPatternRewriter &rewriter)
const override {
344 IntegerAttr isZeroPoison = rewriter.getBoolAttr(
true);
346 if (op.getPredicate() == arc::ZeroCountPredicate::leading) {
347 rewriter.replaceOpWithNewOp<LLVM::CountLeadingZerosOp>(
348 op, adaptor.getInput().getType(), adaptor.getInput(), isZeroPoison);
352 rewriter.replaceOpWithNewOp<LLVM::CountTrailingZerosOp>(
353 op, adaptor.getInput().getType(), adaptor.getInput(), isZeroPoison);
359 using OpConversionPattern::OpConversionPattern;
361 matchAndRewrite(seq::ConstClockOp op, OpAdaptor adaptor,
362 ConversionPatternRewriter &rewriter)
const override {
363 rewriter.replaceOpWithNewOp<LLVM::ConstantOp>(
364 op, rewriter.getI1Type(),
static_cast<int64_t
>(op.getValue()));
369template <
typename OpTy>
372 using OpAdaptor =
typename OpTy::Adaptor;
374 matchAndRewrite(OpTy op, OpAdaptor adaptor,
375 ConversionPatternRewriter &rewriter)
const override {
376 rewriter.replaceOp(op, adaptor.getInput());
390 size_t numStateBytes;
391 llvm::DenseMap<StringRef, StateInfo> states;
392 mlir::FlatSymbolRefAttr initialFnSymbol;
393 mlir::FlatSymbolRefAttr finalFnSymbol;
396template <
typename OpTy>
398 ModelAwarePattern(
const TypeConverter &typeConverter, MLIRContext *
context,
399 llvm::DenseMap<StringRef, ModelInfoMap> &modelInfo)
401 modelInfo(modelInfo) {}
404 Value createPtrToPortState(ConversionPatternRewriter &rewriter, Location loc,
405 Value state,
const StateInfo &port)
const {
406 MLIRContext *ctx = rewriter.getContext();
407 return LLVM::GEPOp::create(rewriter, loc, LLVM::LLVMPointerType::get(ctx),
408 IntegerType::get(ctx, 8), state,
409 LLVM::GEPArg(port.offset));
412 llvm::DenseMap<StringRef, ModelInfoMap> &modelInfo;
417struct SimInstantiateOpLowering
418 :
public ModelAwarePattern<arc::SimInstantiateOp> {
419 using ModelAwarePattern::ModelAwarePattern;
422 matchAndRewrite(arc::SimInstantiateOp op, OpAdaptor adaptor,
423 ConversionPatternRewriter &rewriter)
const final {
424 auto modelIt = modelInfo.find(
425 cast<SimModelInstanceType>(op.getBody().getArgument(0).getType())
428 ModelInfoMap &model = modelIt->second;
430 bool useRuntime = op.getRuntimeModel().has_value();
432 ModuleOp moduleOp = op->getParentOfType<ModuleOp>();
436 ConversionPatternRewriter::InsertionGuard guard(rewriter);
440 Type convertedIndex = typeConverter->convertType(rewriter.getIndexType());
441 Location loc = op.getLoc();
446 auto ptrTy = LLVM::LLVMPointerType::get(getContext());
450 if (op.getRuntimeArgs().has_value()) {
451 SmallVector<int8_t> argStringVec(op.getRuntimeArgsAttr().begin(),
452 op.getRuntimeArgsAttr().end());
453 argStringVec.push_back(
'\0');
454 auto strAttr = mlir::DenseElementsAttr::get(
455 mlir::RankedTensorType::get({(int64_t)argStringVec.size()},
456 rewriter.getI8Type()),
457 llvm::ArrayRef(argStringVec));
459 auto arrayCst = LLVM::ConstantOp::create(
461 LLVM::LLVMArrayType::get(rewriter.getI8Type(), argStringVec.size()),
463 auto cst1 = LLVM::ConstantOp::create(rewriter, loc,
464 rewriter.getI32IntegerAttr(1));
465 runtimeArgs = LLVM::AllocaOp::create(rewriter, loc, ptrTy,
466 arrayCst.getType(), cst1);
467 LLVM::LifetimeStartOp::create(rewriter, loc, runtimeArgs);
468 LLVM::StoreOp::create(rewriter, loc, arrayCst, runtimeArgs);
470 runtimeArgs = LLVM::ZeroOp::create(rewriter, loc, ptrTy).getResult();
473 auto rtModelPtr = LLVM::AddressOfOp::create(rewriter, loc, ptrTy,
474 op.getRuntimeModelAttr())
477 LLVM::CallOp::create(rewriter, loc, {ptrTy},
478 runtime::APICallbacks::symNameAllocInstance,
479 {rtModelPtr, runtimeArgs})
482 if (op.getRuntimeArgs().has_value())
483 LLVM::LifetimeEndOp::create(rewriter, loc, runtimeArgs);
487 FailureOr<LLVM::LLVMFuncOp> mallocFunc =
488 LLVM::lookupOrCreateMallocFn(rewriter, moduleOp, convertedIndex);
489 if (failed(mallocFunc))
492 Value numStateBytes = LLVM::ConstantOp::create(
493 rewriter, loc, convertedIndex, model.numStateBytes);
494 allocated = LLVM::CallOp::create(rewriter, loc, mallocFunc.value(),
495 ValueRange{numStateBytes})
498 LLVM::ConstantOp::create(rewriter, loc, rewriter.getI8Type(), 0);
499 LLVM::MemsetOp::create(rewriter, loc, allocated, zero, numStateBytes,
504 if (model.initialFnSymbol) {
505 auto initialFnType = LLVM::LLVMFunctionType::get(
506 LLVM::LLVMVoidType::get(op.getContext()),
507 {LLVM::LLVMPointerType::get(op.getContext())});
508 LLVM::CallOp::create(rewriter, loc, initialFnType, model.initialFnSymbol,
509 ValueRange{allocated});
514 LLVM::CallOp::create(rewriter, loc, TypeRange{},
515 runtime::APICallbacks::symNameOnInitialized,
519 rewriter.inlineBlockBefore(&adaptor.getBody().getBlocks().front(), op,
523 if (model.finalFnSymbol) {
524 auto finalFnType = LLVM::LLVMFunctionType::get(
525 LLVM::LLVMVoidType::get(op.getContext()),
526 {LLVM::LLVMPointerType::get(op.getContext())});
527 LLVM::CallOp::create(rewriter, loc, finalFnType, model.finalFnSymbol,
528 ValueRange{allocated});
532 LLVM::CallOp::create(rewriter, loc, TypeRange{},
533 runtime::APICallbacks::symNameDeleteInstance,
536 FailureOr<LLVM::LLVMFuncOp> freeFunc =
537 LLVM::lookupOrCreateFreeFn(rewriter, moduleOp);
538 if (failed(freeFunc))
541 LLVM::CallOp::create(rewriter, loc, freeFunc.value(),
542 ValueRange{allocated});
545 rewriter.eraseOp(op);
550struct SimSetInputOpLowering :
public ModelAwarePattern<arc::SimSetInputOp> {
551 using ModelAwarePattern::ModelAwarePattern;
554 matchAndRewrite(arc::SimSetInputOp op, OpAdaptor adaptor,
555 ConversionPatternRewriter &rewriter)
const final {
557 modelInfo.find(cast<SimModelInstanceType>(op.getInstance().getType())
560 ModelInfoMap &model = modelIt->second;
562 auto portIt = model.states.find(op.getInput());
563 if (portIt == model.states.end()) {
566 rewriter.eraseOp(op);
570 StateInfo &port = portIt->second;
571 Value statePtr = createPtrToPortState(rewriter, op.getLoc(),
572 adaptor.getInstance(), port);
573 rewriter.replaceOpWithNewOp<LLVM::StoreOp>(op, adaptor.getValue(),
580struct SimGetPortOpLowering :
public ModelAwarePattern<arc::SimGetPortOp> {
581 using ModelAwarePattern::ModelAwarePattern;
584 matchAndRewrite(arc::SimGetPortOp op, OpAdaptor adaptor,
585 ConversionPatternRewriter &rewriter)
const final {
587 modelInfo.find(cast<SimModelInstanceType>(op.getInstance().getType())
590 ModelInfoMap &model = modelIt->second;
592 auto type = typeConverter->convertType(op.getValue().getType());
595 auto portIt = model.states.find(op.getPort());
596 if (portIt == model.states.end()) {
599 rewriter.replaceOpWithNewOp<LLVM::ConstantOp>(op, type, 0);
603 StateInfo &port = portIt->second;
604 Value statePtr = createPtrToPortState(rewriter, op.getLoc(),
605 adaptor.getInstance(), port);
606 rewriter.replaceOpWithNewOp<LLVM::LoadOp>(op, type, statePtr);
612struct SimStepOpLowering :
public ModelAwarePattern<arc::SimStepOp> {
613 using ModelAwarePattern::ModelAwarePattern;
616 matchAndRewrite(arc::SimStepOp op, OpAdaptor adaptor,
617 ConversionPatternRewriter &rewriter)
const final {
618 StringRef modelName = cast<SimModelInstanceType>(op.getInstance().getType())
622 if (adaptor.getTimePostIncrement()) {
624 OpBuilder::InsertionGuard g(rewriter);
625 rewriter.setInsertionPointAfter(op);
627 arc::SimGetTimeOp::create(rewriter, op.getLoc(), op.getInstance());
628 auto newTime = LLVM::AddOp::create(rewriter, op.getLoc(), oldTime,
629 adaptor.getTimePostIncrement());
630 arc::SimSetTimeOp::create(rewriter, op.getLoc(), op.getInstance(),
634 StringAttr evalFunc =
636 rewriter.replaceOpWithNewOp<LLVM::CallOp>(op, mlir::TypeRange(), evalFunc,
637 adaptor.getInstance());
646 using OpConversionPattern::OpConversionPattern;
649 matchAndRewrite(arc::SimGetTimeOp op, OpAdaptor adaptor,
650 ConversionPatternRewriter &rewriter)
const final {
652 rewriter.replaceOpWithNewOp<LLVM::LoadOp>(op, rewriter.getI64Type(),
653 adaptor.getInstance());
661 using OpConversionPattern::OpConversionPattern;
664 matchAndRewrite(arc::SimSetTimeOp op, OpAdaptor adaptor,
665 ConversionPatternRewriter &rewriter)
const final {
667 rewriter.replaceOpWithNewOp<LLVM::StoreOp>(op, adaptor.getTime(),
668 adaptor.getInstance());
676 Value getOrCreate(OpBuilder &b, StringRef formatStr) {
677 auto it = cache.find(formatStr);
678 if (it != cache.end()) {
679 return LLVM::AddressOfOp::create(b,
b.getUnknownLoc(), it->second);
682 Location loc =
b.getUnknownLoc();
683 LLVM::GlobalOp global;
685 OpBuilder::InsertionGuard guard(b);
687 b.getInsertionBlock()->getParent()->getParentOfType<ModuleOp>();
688 b.setInsertionPointToStart(m.getBody());
690 SmallVector<char> strVec(formatStr.begin(), formatStr.end());
693 auto name = llvm::formatv(
"_arc_str_{0}", cache.size()).str();
694 auto globalType = LLVM::LLVMArrayType::get(
b.getI8Type(), strVec.size());
695 global = LLVM::GlobalOp::create(b, loc, globalType,
true,
696 LLVM::Linkage::Internal,
697 name,
b.getStringAttr(strVec),
701 cache[formatStr] = global;
702 return LLVM::AddressOfOp::create(b, loc, global);
706 llvm::StringMap<LLVM::GlobalOp> cache;
709FailureOr<LLVM::CallOp> emitPrintfCall(OpBuilder &builder, Location loc,
710 StringCache &cache, StringRef formatStr,
713 builder.getInsertionBlock()->getParent()->getParentOfType<ModuleOp>();
715 MLIRContext *ctx = builder.getContext();
716 auto printfFunc = LLVM::lookupOrCreateFn(builder, moduleOp,
"printf",
717 LLVM::LLVMPointerType::get(ctx),
718 LLVM::LLVMVoidType::get(ctx),
true);
719 if (failed(printfFunc))
722 Value formatStrPtr = cache.getOrCreate(builder, formatStr);
723 SmallVector<Value> argsVec(1, formatStrPtr);
724 argsVec.append(args.begin(), args.end());
725 return LLVM::CallOp::create(builder, loc, printfFunc.value(), argsVec);
731struct SimEmitValueOpLowering
733 SimEmitValueOpLowering(
const TypeConverter &typeConverter,
734 MLIRContext *
context, StringCache &formatStringCache)
736 formatStringCache(formatStringCache) {}
739 matchAndRewrite(arc::SimEmitValueOp op, OpAdaptor adaptor,
740 ConversionPatternRewriter &rewriter)
const final {
741 auto valueType = dyn_cast<IntegerType>(adaptor.getValue().getType());
745 Location loc = op.getLoc();
747 ModuleOp moduleOp = op->getParentOfType<ModuleOp>();
751 SmallVector<Value> printfVariadicArgs;
752 SmallString<16> printfFormatStr;
753 int remainingBits = valueType.getWidth();
754 Value value = adaptor.getValue();
758 constexpr llvm::StringRef intFormatter =
"llx";
759 auto intType = IntegerType::get(getContext(), 64);
760 Value shiftValue = LLVM::ConstantOp::create(
761 rewriter, loc, rewriter.getIntegerAttr(valueType, intType.getWidth()));
763 if (valueType.getWidth() < intType.getWidth()) {
764 int width = llvm::divideCeil(valueType.getWidth(), 4);
765 printfFormatStr = llvm::formatv(
"%0{0}{1}", width, intFormatter);
766 printfVariadicArgs.push_back(
767 LLVM::ZExtOp::create(rewriter, loc, intType, value));
772 int otherChunkWidth = intType.getWidth() / 4;
773 int firstChunkWidth =
774 llvm::divideCeil(valueType.getWidth() % intType.getWidth(), 4);
775 if (firstChunkWidth == 0) {
776 firstChunkWidth = otherChunkWidth;
779 std::string firstChunkFormat =
780 llvm::formatv(
"%0{0}{1}", firstChunkWidth, intFormatter);
781 std::string otherChunkFormat =
782 llvm::formatv(
"%0{0}{1}", otherChunkWidth, intFormatter);
784 for (
int i = 0; remainingBits > 0; ++i) {
787 printfVariadicArgs.push_back(
788 LLVM::TruncOp::create(rewriter, loc, intType, value));
791 printfFormatStr.append(i == 0 ? firstChunkFormat : otherChunkFormat);
794 LLVM::LShrOp::create(rewriter, loc, value, shiftValue).getResult();
795 remainingBits -= intType.getWidth();
799 std::reverse(printfVariadicArgs.begin(), printfVariadicArgs.end());
801 SmallString<16> formatStr = adaptor.getValueName();
802 formatStr.append(
" = ");
803 formatStr.append(printfFormatStr);
804 formatStr.append(
"\n");
806 auto callOp = emitPrintfCall(rewriter, op->getLoc(), formatStringCache,
807 formatStr, printfVariadicArgs);
810 rewriter.replaceOp(op, *callOp);
815 StringCache &formatStringCache;
824 SmallVector<FmtDescriptor> descriptors;
825 SmallVector<Value> args;
832static Value reg2mem(ConversionPatternRewriter &rewriter, Location loc,
835 int64_t origBitwidth = cast<IntegerType>(value.getType()).getWidth();
836 int64_t bitwidth = llvm::divideCeil(origBitwidth, 64) * 64;
837 int64_t numWords = bitwidth / 64;
840 LLVM::ConstantOp alloca_size =
841 LLVM::ConstantOp::create(rewriter, loc, rewriter.getI32Type(), numWords);
842 auto ptrType = LLVM::LLVMPointerType::get(rewriter.getContext());
843 auto allocaOp = LLVM::AllocaOp::create(rewriter, loc, ptrType,
844 rewriter.getI64Type(), alloca_size);
845 LLVM::LifetimeStartOp::create(rewriter, loc, allocaOp);
849 for (int64_t wordIdx = 0; wordIdx < numWords; ++wordIdx) {
850 Value cst = LLVM::ConstantOp::create(
851 rewriter, loc, rewriter.getIntegerType(origBitwidth), wordIdx * 64);
852 Value v = LLVM::LShrOp::create(rewriter, loc, value, cst);
853 if (origBitwidth > 64) {
854 v = LLVM::TruncOp::create(rewriter, loc, rewriter.getI64Type(), v);
855 }
else if (origBitwidth < 64) {
856 v = LLVM::ZExtOp::create(rewriter, loc, rewriter.getI64Type(), v);
858 Value gep = LLVM::GEPOp::create(rewriter, loc, ptrType,
859 rewriter.getI64Type(), allocaOp, {wordIdx});
860 LLVM::StoreOp::create(rewriter, loc, v, gep);
867static FailureOr<FormatInfo>
868foldFormatString(ConversionPatternRewriter &rewriter, Value fstringValue,
869 StringCache &cache) {
870 Operation *op = fstringValue.getDefiningOp();
871 return llvm::TypeSwitch<Operation *, FailureOr<FormatInfo>>(op)
872 .Case<sim::FormatCharOp>(
873 [&](sim::FormatCharOp op) -> FailureOr<FormatInfo> {
874 FmtDescriptor
d = FmtDescriptor::createChar();
875 return FormatInfo{{
d}, {op.getValue()}};
877 .Case<sim::FormatDecOp>([&](sim::FormatDecOp op)
878 -> FailureOr<FormatInfo> {
879 FmtDescriptor
d = FmtDescriptor::createInt(
880 op.getValue().getType().getWidth(), 10, op.getIsLeftAligned(),
881 op.getSpecifierWidth().value_or(-1),
false, op.getIsSigned());
882 return FormatInfo{{
d}, {reg2mem(rewriter, op.getLoc(), op.getValue())}};
884 .Case<sim::FormatHexOp>([&](sim::FormatHexOp op)
885 -> FailureOr<FormatInfo> {
886 FmtDescriptor
d = FmtDescriptor::createInt(
887 op.getValue().getType().getWidth(), 16, op.getIsLeftAligned(),
888 op.getSpecifierWidth().value_or(-1), op.getIsHexUppercase(),
false);
889 return FormatInfo{{
d}, {reg2mem(rewriter, op.getLoc(), op.getValue())}};
891 .Case<sim::FormatOctOp>([&](sim::FormatOctOp op)
892 -> FailureOr<FormatInfo> {
893 FmtDescriptor
d = FmtDescriptor::createInt(
894 op.getValue().getType().getWidth(), 8, op.getIsLeftAligned(),
895 op.getSpecifierWidth().value_or(-1),
false,
false);
896 return FormatInfo{{
d}, {reg2mem(rewriter, op.getLoc(), op.getValue())}};
898 .Case<sim::FormatLiteralOp>(
899 [&](sim::FormatLiteralOp op) -> FailureOr<FormatInfo> {
900 if (op.getLiteral().size() < 8 &&
901 op.getLiteral().find(
'\0') == StringRef::npos) {
904 FmtDescriptor::createSmallLiteral(op.getLiteral());
905 return FormatInfo{{
d}, {}};
908 FmtDescriptor::createLiteral(op.getLiteral().size());
909 Value value = cache.getOrCreate(rewriter, op.getLiteral());
910 return FormatInfo{{
d}, {value}};
912 .Case<sim::FormatStringConcatOp>(
913 [&](sim::FormatStringConcatOp op) -> FailureOr<FormatInfo> {
914 auto fmt = foldFormatString(rewriter, op.getInputs()[0], cache);
917 for (
auto input : op.getInputs().drop_front()) {
918 auto next = foldFormatString(rewriter, input, cache);
921 fmt->descriptors.append(next->descriptors);
922 fmt->args.append(next->args);
927 [](Operation *op) -> FailureOr<FormatInfo> {
return failure(); });
930FailureOr<LLVM::CallOp> emitFmtCall(OpBuilder &builder, Location loc,
931 StringCache &stringCache,
932 ArrayRef<FmtDescriptor> descriptors,
935 builder.getInsertionBlock()->getParent()->getParentOfType<ModuleOp>();
937 MLIRContext *ctx = builder.getContext();
938 auto func = LLVM::lookupOrCreateFn(
939 builder, moduleOp, runtime::APICallbacks::symNameFormat,
940 LLVM::LLVMPointerType::get(ctx), LLVM::LLVMVoidType::get(ctx),
true);
944 StringRef rawDescriptors(
reinterpret_cast<const char *
>(descriptors.data()),
945 descriptors.size() *
sizeof(FmtDescriptor));
946 Value fmtPtr = stringCache.getOrCreate(builder, rawDescriptors);
948 SmallVector<Value> argsVec(1, fmtPtr);
949 argsVec.append(args.begin(), args.end());
950 auto result = LLVM::CallOp::create(builder, loc, func.value(), argsVec);
952 for (Value arg : args) {
953 Operation *definingOp = arg.getDefiningOp();
954 if (
auto alloca = dyn_cast_if_present<LLVM::AllocaOp>(definingOp)) {
955 LLVM::LifetimeEndOp::create(builder, loc, arg);
962struct SimPrintFormattedProcOpLowering
964 SimPrintFormattedProcOpLowering(
const TypeConverter &typeConverter,
966 StringCache &stringCache)
968 stringCache(stringCache) {}
971 matchAndRewrite(sim::PrintFormattedProcOp op, OpAdaptor adaptor,
972 ConversionPatternRewriter &rewriter)
const override {
973 auto formatInfo = foldFormatString(rewriter, op.getInput(), stringCache);
974 if (failed(formatInfo))
975 return rewriter.notifyMatchFailure(op,
"unsupported format string");
978 formatInfo->descriptors.push_back(FmtDescriptor());
980 auto result = emitFmtCall(rewriter, op.getLoc(), stringCache,
981 formatInfo->descriptors, formatInfo->args);
984 rewriter.replaceOp(op, result.value());
989 StringCache &stringCache;
993 using OpConversionPattern::OpConversionPattern;
996 matchAndRewrite(arc::TerminateOp op, OpAdaptor adaptor,
997 ConversionPatternRewriter &rewriter)
const override {
998 auto loc = op.getLoc();
1000 auto i8Type = rewriter.getI8Type();
1001 auto ptrType = LLVM::LLVMPointerType::get(rewriter.getContext());
1003 Value flagPtr = LLVM::GEPOp::create(
1004 rewriter, loc, ptrType, i8Type, adaptor.getStorage(),
1005 ArrayRef<LLVM::GEPArg>{arc::kTerminateFlagOffset});
1007 uint8_t statusCode = op.getSuccess() ? 1 : 2;
1008 Value codeVal = LLVM::ConstantOp::create(
1009 rewriter, loc, i8Type, rewriter.getI8IntegerAttr(statusCode));
1011 LLVM::StoreOp::create(rewriter, loc, codeVal, flagPtr);
1013 rewriter.eraseOp(op);
1020static LogicalResult
convert(arc::ExecuteOp op, arc::ExecuteOp::Adaptor adaptor,
1021 ConversionPatternRewriter &rewriter,
1022 const TypeConverter &converter) {
1024 if (failed(rewriter.convertRegionTypes(&op.getBody(), converter)))
1030 auto *blockBefore = rewriter.getInsertionBlock();
1032 rewriter.splitBlock(blockBefore, rewriter.getInsertionPoint());
1035 rewriter.setInsertionPointToEnd(blockBefore);
1036 mlir::cf::BranchOp::create(rewriter, op.getLoc(), &op.getBody().front(),
1037 adaptor.getInputs());
1041 for (
auto &block : op.getBody()) {
1042 auto outputOp = dyn_cast<arc::OutputOp>(block.getTerminator());
1045 rewriter.setInsertionPointToEnd(&block);
1046 rewriter.replaceOpWithNewOp<mlir::cf::BranchOp>(outputOp, blockAfter,
1047 outputOp.getOperands());
1051 rewriter.inlineRegionBefore(op.getBody(), blockAfter);
1055 SmallVector<Value> args;
1056 args.reserve(op.getNumResults());
1057 for (
auto result : op.getResults())
1058 args.push_back(blockAfter->addArgument(result.getType(), result.getLoc()));
1059 rewriter.replaceOp(op, args);
1060 auto conversion = converter.convertBlockSignature(blockAfter);
1063 rewriter.applySignatureConversion(blockAfter, *conversion, &converter);
1071template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
1072static LLVM::GlobalOp
1074 SmallVectorImpl<T> &data,
1075 unsigned alignment =
alignof(T)) {
1076 auto intType = builder.getIntegerType(8 *
sizeof(T));
1077 Attribute denseAttr = mlir::DenseElementsAttr::get(
1078 mlir::RankedTensorType::get({(int64_t)data.size()}, intType),
1079 llvm::ArrayRef(data));
1080 auto globalOp = LLVM::GlobalOp::create(
1081 builder, loc, LLVM::LLVMArrayType::get(intType, data.size()),
1082 true, LLVM::Linkage::Internal,
1083 builder.getStringAttr(symName), denseAttr);
1084 globalOp.setAlignmentAttr(builder.getI64IntegerAttr(alignment));
1089template <
typename T>
1090static LLVM::GlobalOp
1093 SmallVectorImpl<T> &array) {
1095 static_assert(std::is_standard_layout<T>(),
1096 "Runtime struct must have standard layout");
1097 int64_t numBytes =
sizeof(T) * array.size();
1098 Attribute denseAttr = mlir::DenseElementsAttr::get(
1099 mlir::RankedTensorType::get({numBytes}, builder.getI8Type()),
1100 llvm::ArrayRef(
reinterpret_cast<uint8_t *
>(array.data()), numBytes));
1101 auto globalOp = LLVM::GlobalOp::create(
1102 builder, loc, LLVM::LLVMArrayType::get(builder.getI8Type(), numBytes),
1103 true, LLVM::Linkage::Internal,
1104 builder.getStringAttr(symName), denseAttr,
alignof(T));
1110 using OpConversionPattern::OpConversionPattern;
1117 ConversionPatternRewriter &rewriter)
const {
1118 if (!op.getTraceTaps().has_value() || op.getTraceTaps()->empty())
1121 SmallVector<char> namesArray;
1122 SmallVector<ArcTraceTap> tapArray;
1123 tapArray.reserve(op.getTraceTaps()->size());
1124 for (
auto attr : op.getTraceTapsAttr()) {
1125 auto tap = cast<TraceTapAttr>(attr);
1126 assert(!tap.getNames().empty() &&
1127 "Expected trace tap to have at least one name");
1128 for (
auto alias : tap.getNames()) {
1129 auto aliasStr = cast<StringAttr>(alias);
1130 namesArray.append(aliasStr.begin(), aliasStr.end());
1131 namesArray.push_back(
'\0');
1135 tapStruct.
nameOffset = namesArray.size() - 1;
1136 tapStruct.
typeBits = tap.getSigType().getValue().getIntOrFloatBitWidth();
1138 tapArray.emplace_back(tapStruct);
1140 auto ptrTy = LLVM::LLVMPointerType::get(getContext());
1142 rewriter, op.getLoc(),
"_arc_tap_names_" + op.getName(), namesArray);
1144 rewriter, op.getLoc(),
"_arc_trace_taps_" + op.getName(), tapArray);
1154 auto traceInfoStructType = LLVM::LLVMStructType::getLiteral(
1156 {rewriter.getI64Type(), ptrTy, ptrTy, rewriter.getI64Type()});
1158 "Unexpected size of ArcModelTraceInfo struct");
1160 auto globalSymName =
1161 rewriter.getStringAttr(
"_arc_trace_info_" + op.getName());
1162 auto traceInfoGlobalOp = LLVM::GlobalOp::create(
1163 rewriter, op.getLoc(), traceInfoStructType,
1164 false, LLVM::Linkage::Internal, globalSymName,
1166 OpBuilder::InsertionGuard g(rewriter);
1169 Region &initRegion = traceInfoGlobalOp.getInitializerRegion();
1170 Block *initBlock = rewriter.createBlock(&initRegion);
1171 rewriter.setInsertionPointToStart(initBlock);
1173 auto numTraceTapsCst = LLVM::ConstantOp::create(
1174 rewriter, op.getLoc(), rewriter.getI64IntegerAttr(tapArray.size()));
1175 auto traceTapArrayAddr =
1176 LLVM::AddressOfOp::create(rewriter, op.getLoc(), traceTapsArrayGlobal);
1177 auto tapNameArrayAddr =
1178 LLVM::AddressOfOp::create(rewriter, op.getLoc(), namesGlobal);
1179 auto bufferCapacityCst = LLVM::ConstantOp::create(
1180 rewriter, op.getLoc(),
1181 rewriter.getI64IntegerAttr(runtime::defaultTraceBufferCapacity));
1184 LLVM::PoisonOp::create(rewriter, op.getLoc(), traceInfoStructType);
1188 LLVM::InsertValueOp::create(rewriter, op.getLoc(), initStruct,
1189 numTraceTapsCst, ArrayRef<int64_t>{0});
1191 "Unexpected offset of field numTraceTaps");
1194 LLVM::InsertValueOp::create(rewriter, op.getLoc(), initStruct,
1195 traceTapArrayAddr, ArrayRef<int64_t>{1});
1197 "Unexpected offset of field traceTaps");
1200 LLVM::InsertValueOp::create(rewriter, op.getLoc(), initStruct,
1201 tapNameArrayAddr, ArrayRef<int64_t>{2});
1203 "Unexpected offset of field traceTapNames");
1206 LLVM::InsertValueOp::create(rewriter, op.getLoc(), initStruct,
1207 bufferCapacityCst, ArrayRef<int64_t>{3});
1209 "Unexpected offset of field traceBufferCapacity");
1210 LLVM::ReturnOp::create(rewriter, op.getLoc(), initStruct);
1212 return traceInfoGlobalOp;
1218 ConversionPatternRewriter &rewriter)
const final {
1220 auto ptrTy = LLVM::LLVMPointerType::get(getContext());
1221 auto modelInfoStructType = LLVM::LLVMStructType::getLiteral(
1223 {rewriter.getI64Type(), rewriter.getI64Type(), ptrTy, ptrTy});
1225 "Unexpected size of ArcRuntimeModelInfo struct");
1227 rewriter.setInsertionPoint(op);
1231 SmallVector<char, 16> modNameArray(op.getName().begin(),
1232 op.getName().end());
1233 modNameArray.push_back(
'\0');
1234 auto nameGlobalType =
1235 LLVM::LLVMArrayType::get(rewriter.getI8Type(), modNameArray.size());
1236 auto globalSymName =
1237 rewriter.getStringAttr(
"_arc_mod_name_" + op.getName());
1238 auto nameGlobal = LLVM::GlobalOp::create(
1239 rewriter, op.getLoc(), nameGlobalType,
true,
1240 LLVM::Linkage::Internal,
1241 globalSymName, rewriter.getStringAttr(modNameArray),
1248 auto modInfoGlobalOp =
1249 LLVM::GlobalOp::create(rewriter, op.getLoc(), modelInfoStructType,
1250 false, LLVM::Linkage::External,
1251 op.getSymName(), Attribute{});
1254 Region &initRegion = modInfoGlobalOp.getInitializerRegion();
1255 Block *initBlock = rewriter.createBlock(&initRegion);
1256 rewriter.setInsertionPointToStart(initBlock);
1257 auto apiVersionCst = LLVM::ConstantOp::create(
1259 auto numStateBytesCst = LLVM::ConstantOp::create(rewriter, op.getLoc(),
1260 op.getNumStateBytesAttr());
1262 LLVM::AddressOfOp::create(rewriter, op.getLoc(), nameGlobal);
1264 if (traceInfoGlobal)
1266 LLVM::AddressOfOp::create(rewriter, op.getLoc(), traceInfoGlobal);
1268 traceInfoPtr = LLVM::ZeroOp::create(rewriter, op.getLoc(), ptrTy);
1271 LLVM::PoisonOp::create(rewriter, op.getLoc(), modelInfoStructType);
1274 initStruct = LLVM::InsertValueOp::create(
1275 rewriter, op.getLoc(), initStruct, apiVersionCst, ArrayRef<int64_t>{0});
1277 "Unexpected offset of field apiVersion");
1280 LLVM::InsertValueOp::create(rewriter, op.getLoc(), initStruct,
1281 numStateBytesCst, ArrayRef<int64_t>{1});
1283 "Unexpected offset of field numStateBytes");
1285 initStruct = LLVM::InsertValueOp::create(rewriter, op.getLoc(), initStruct,
1286 nameAddr, ArrayRef<int64_t>{2});
1288 "Unexpected offset of field modelName");
1290 initStruct = LLVM::InsertValueOp::create(
1291 rewriter, op.getLoc(), initStruct, traceInfoPtr, ArrayRef<int64_t>{3});
1293 "Unexpected offset of field traceInfo");
1295 LLVM::ReturnOp::create(rewriter, op.getLoc(), initStruct);
1297 rewriter.replaceOp(op, modInfoGlobalOp);
1307struct LowerArcToLLVMPass
1308 :
public circt::impl::LowerArcToLLVMBase<LowerArcToLLVMPass> {
1309 void runOnOperation()
override;
1313void LowerArcToLLVMPass::runOnOperation() {
1317 DenseMap<Region *, hw::ConstantOp> zeros;
1318 getOperation().walk([&](Operation *op) {
1319 if (op->hasTrait<OpTrait::ConstantLike>())
1321 for (
auto result : op->getResults()) {
1322 auto type = dyn_cast<IntegerType>(result.getType());
1323 if (!type || type.getWidth() != 0)
1325 auto *region = op->getParentRegion();
1326 auto &zero = zeros[region];
1328 auto builder = OpBuilder::atBlockBegin(®ion->front());
1332 result.replaceAllUsesWith(zero);
1348 LLVMConversionTarget target(getContext());
1349 target.addLegalOp<mlir::ModuleOp>();
1350 target.addLegalOp<scf::YieldOp>();
1355 target.addLegalOp<sim::FormatLiteralOp, sim::FormatDecOp, sim::FormatHexOp,
1356 sim::FormatBinOp, sim::FormatOctOp, sim::FormatCharOp,
1357 sim::FormatStringConcatOp>();
1360 LLVMTypeConverter converter(&getContext());
1361 converter.addConversion([&](seq::ClockType type) {
1362 return IntegerType::get(type.getContext(), 1);
1364 converter.addConversion([&](StorageType type) {
1365 return LLVM::LLVMPointerType::get(type.getContext());
1367 converter.addConversion([&](MemoryType type) {
1368 return LLVM::LLVMPointerType::get(type.getContext());
1370 converter.addConversion([&](StateType type) {
1371 return LLVM::LLVMPointerType::get(type.getContext());
1373 converter.addConversion([&](SimModelInstanceType type) {
1374 return LLVM::LLVMPointerType::get(type.getContext());
1376 converter.addConversion([&](sim::FormatStringType type) {
1377 return LLVM::LLVMPointerType::get(type.getContext());
1379 converter.addConversion([&](llhd::TimeType type) {
1381 return IntegerType::get(type.getContext(), 64);
1388 populateSCFToControlFlowConversionPatterns(
patterns);
1389 populateFuncToLLVMConversionPatterns(converter,
patterns);
1390 cf::populateControlFlowToLLVMConversionPatterns(converter,
patterns);
1391 arith::populateArithToLLVMConversionPatterns(converter,
patterns);
1392 index::populateIndexToLLVMConversionPatterns(converter,
patterns);
1393 populateAnyFunctionOpInterfaceTypeConversionPattern(
patterns, converter);
1396 DenseMap<std::pair<Type, ArrayAttr>, LLVM::GlobalOp> constAggregateGlobalsMap;
1398 std::optional<HWToLLVMArraySpillCache> spillCacheOpt =
1401 OpBuilder spillBuilder(getOperation());
1402 spillCacheOpt->spillNonHWOps(spillBuilder, converter, getOperation());
1405 constAggregateGlobalsMap, spillCacheOpt);
1413 AllocMemoryOpLowering,
1414 AllocStateLikeOpLowering<arc::AllocStateOp>,
1415 AllocStateLikeOpLowering<arc::RootInputOp>,
1416 AllocStateLikeOpLowering<arc::RootOutputOp>,
1417 AllocStorageOpLowering,
1418 ClockGateOpLowering,
1420 CurrentTimeOpLowering,
1421 IntToTimeOpLowering,
1422 MemoryReadOpLowering,
1423 MemoryWriteOpLowering,
1425 ReplaceOpWithInputPattern<seq::ToClockOp>,
1426 ReplaceOpWithInputPattern<seq::FromClockOp>,
1428 SeqConstClockLowering,
1429 SimGetTimeOpLowering,
1430 SimSetTimeOpLowering,
1431 StateReadOpLowering,
1432 StateWriteOpLowering,
1433 StorageGetOpLowering,
1434 TerminateOpLowering,
1435 TimeToIntOpLowering,
1437 >(converter, &getContext());
1441 StringCache stringCache;
1442 patterns.add<SimEmitValueOpLowering, SimPrintFormattedProcOpLowering>(
1443 converter, &getContext(), stringCache);
1445 auto &modelInfo = getAnalysis<ModelInfoAnalysis>();
1446 llvm::DenseMap<StringRef, ModelInfoMap> modelMap(modelInfo.infoMap.size());
1447 for (
auto &[_, modelInfo] : modelInfo.infoMap) {
1448 llvm::DenseMap<StringRef, StateInfo> states(modelInfo.states.size());
1449 for (StateInfo &stateInfo : modelInfo.states)
1450 states.insert({stateInfo.name, stateInfo});
1453 ModelInfoMap{modelInfo.numStateBytes, std::move(states),
1454 modelInfo.initialFnSym, modelInfo.finalFnSym}});
1457 patterns.add<SimInstantiateOpLowering, SimSetInputOpLowering,
1458 SimGetPortOpLowering, SimStepOpLowering>(
1459 converter, &getContext(), modelMap);
1462 ConversionConfig config;
1463 config.allowPatternRollback =
false;
1464 if (failed(applyFullConversion(getOperation(), target, std::move(
patterns),
1466 signalPassFailure();
1470 return std::make_unique<LowerArcToLLVMPass>();
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static LLVM::GlobalOp buildGlobalConstantIntArray(OpBuilder &builder, Location loc, Twine symName, SmallVectorImpl< T > &data, unsigned alignment=alignof(T))
static LLVM::GlobalOp buildGlobalConstantRuntimeStructArray(OpBuilder &builder, Location loc, Twine symName, SmallVectorImpl< T > &array)
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.
uint32_t typeBits
Bit width of the traced signal.
uint64_t stateOffset
Byte offset of the traced value within the model state.
uint64_t nameOffset
Byte offset to the null terminator of this signal's last alias in the names array.
uint32_t reserved
Padding and reserved for future use.
LLVM::GlobalOp buildTraceInfoStruct(arc::RuntimeModelOp &op, ConversionPatternRewriter &rewriter) const
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...