379 ConversionPatternRewriter &rewriter)
const override;
401 if (sourceElementType == targetElementType)
404 auto targetIntType = dyn_cast<IntegerType>(targetElementType);
411 if (
auto sourceFloatType = dyn_cast<FloatType>(sourceElementType)) {
412 if (sourceFloatType.getWidth() != targetIntType.getWidth())
421 if (!isa<IndexType>(sourceElementType))
425 unsigned width = targetIntType.getWidth();
427 if (
auto intAttr = dyn_cast<IntegerAttr>(attr))
428 return IntegerAttr::get(targetIntType,
429 intAttr.getValue().sextOrTrunc(width));
432 return values.mapValues(targetIntType, [&](
const APInt &value) {
433 return value.sextOrTrunc(width);
437 if (
auto denseAttr = dyn_cast<DenseIntElementsAttr>(attr))
438 return retypeValues(denseAttr);
440 if (
auto sparseAttr = dyn_cast<SparseElementsAttr>(attr))
441 return SparseElementsAttr::get(
442 cast<ShapedType>(attr.getType()).clone(targetIntType),
443 sparseAttr.getIndices(),
444 retypeValues(cast<DenseIntElementsAttr>(sparseAttr.getValues())));
450 if (
auto resourceAttr = dyn_cast<DenseResourceElementsAttr>(attr)) {
451 if (width != IndexType::kInternalStorageBitWidth)
453 return DenseResourceElementsAttr::get(
454 cast<ShapedType>(attr.getType()).clone(targetIntType),
455 resourceAttr.getRawHandle());
462ConstantOpLowering::matchAndRewrite(arith::ConstantOp op, OpAdaptor adaptor,
463 ConversionPatternRewriter &rewriter)
const {
464 Type resultType = getTypeConverter()->convertType(op.getType());
466 return rewriter.notifyMatchFailure(op,
"failed to convert result type");
470 return rewriter.notifyMatchFailure(
471 op,
"failed to convert value attribute to the converted result type");
476 DictionaryAttr discardableAttrs = op->getDiscardableAttrDictionary();
478 LLVM::ConstantOp::create(rewriter, op.getLoc(), resultType, value);
479 constantOp->setDiscardableAttrs(discardableAttrs);
480 rewriter.replaceOp(op, constantOp);
488template <
typename OpTy,
typename ExtCastTy>
489LogicalResult IndexCastOpLowering<OpTy, ExtCastTy>::matchAndRewrite(
490 OpTy op,
typename OpTy::Adaptor adaptor,
491 ConversionPatternRewriter &rewriter)
const {
492 Type resultType = op.getResult().getType();
493 Type targetElementType =
495 Type sourceElementType =
500 if (targetBits == sourceBits) {
501 rewriter.replaceOp(op, adaptor.getIn());
508 if (isa<MemRefType>(op.getIn().getType())) {
509 rewriter.replaceOp(op, adaptor.getIn());
513 bool isNonNeg =
false;
514 if constexpr (std::is_same_v<ExtCastTy, LLVM::ZExtOp>)
515 isNonNeg = op.getNonNeg();
518 Type operandType = adaptor.getIn().getType();
519 if (!isa<LLVM::LLVMArrayType>(operandType)) {
520 Type targetType = this->typeConverter->convertType(resultType);
521 if (targetBits < sourceBits) {
522 rewriter.replaceOpWithNewOp<LLVM::TruncOp>(op, targetType,
525 auto extOp = rewriter.replaceOpWithNewOp<ExtCastTy>(op, targetType,
527 if constexpr (std::is_same_v<ExtCastTy, LLVM::ZExtOp>)
528 extOp.setNonNeg(isNonNeg);
533 if (!isa<VectorType>(resultType))
534 return rewriter.notifyMatchFailure(op,
"expected vector result type");
537 op.getOperation(), adaptor.getOperands(), *(this->getTypeConverter()),
538 [&](Type llvm1DVectorTy,
ValueRange operands) -> Value {
539 typename OpTy::Adaptor adaptor(operands);
540 if (targetBits < sourceBits) {
541 return LLVM::TruncOp::create(rewriter, op.getLoc(), llvm1DVectorTy,
544 auto extOp = ExtCastTy::create(rewriter, op.getLoc(), llvm1DVectorTy,
546 if constexpr (std::is_same_v<ExtCastTy, LLVM::ZExtOp>) {
548 extOp.setNonNeg(
true);
559LogicalResult AddUIExtendedOpLowering::matchAndRewrite(
560 arith::AddUIExtendedOp op, OpAdaptor adaptor,
561 ConversionPatternRewriter &rewriter)
const {
562 Type operandType = adaptor.getLhs().getType();
563 Type sumResultType = op.getSum().getType();
564 Type overflowResultType = op.getOverflow().getType();
569 MLIRContext *ctx = rewriter.getContext();
570 Location loc = op.getLoc();
573 if (!isa<LLVM::LLVMArrayType>(operandType)) {
574 Type newSumType = typeConverter->convertType(sumResultType);
575 Type newOverflowType = typeConverter->convertType(overflowResultType);
577 LLVM::LLVMStructType::getLiteral(ctx, {newSumType, newOverflowType});
578 Value addOverflow = LLVM::UAddWithOverflowOp::create(
579 rewriter, loc, structType, adaptor.getLhs(), adaptor.getRhs());
581 LLVM::ExtractValueOp::create(rewriter, loc, addOverflow, 0);
582 Value overflowExtracted =
583 LLVM::ExtractValueOp::create(rewriter, loc, addOverflow, 1);
584 rewriter.replaceOp(op, {sumExtracted, overflowExtracted});
588 if (!isa<VectorType>(sumResultType))
589 return rewriter.notifyMatchFailure(loc,
"expected vector result types");
591 return rewriter.notifyMatchFailure(loc,
592 "ND vector types are not supported yet");
599LogicalResult SubUIExtendedOpLowering::matchAndRewrite(
600 arith::SubUIExtendedOp op, OpAdaptor adaptor,
601 ConversionPatternRewriter &rewriter)
const {
602 Type operandType = adaptor.getLhs().getType();
603 Type diffResultType = op.getDiff().getType();
604 Type borrowResultType = op.getBorrow().getType();
609 MLIRContext *ctx = rewriter.getContext();
610 Location loc = op.getLoc();
613 if (!isa<LLVM::LLVMArrayType>(operandType)) {
614 Type newBorrowType = typeConverter->convertType(borrowResultType);
616 LLVM::LLVMStructType::getLiteral(ctx, {diffResultType, newBorrowType});
617 Value subOverflow = LLVM::USubWithOverflowOp::create(
618 rewriter, loc, structType, adaptor.getLhs(), adaptor.getRhs());
619 Value diffExtracted =
620 LLVM::ExtractValueOp::create(rewriter, loc, subOverflow, 0);
621 Value borrowExtracted =
622 LLVM::ExtractValueOp::create(rewriter, loc, subOverflow, 1);
623 rewriter.replaceOp(op, {diffExtracted, borrowExtracted});
627 if (!isa<VectorType>(diffResultType))
628 return rewriter.notifyMatchFailure(loc,
"expected vector result types");
630 return rewriter.notifyMatchFailure(loc,
631 "ND vector types are not supported yet");
638template <
typename ArithMulOp,
bool IsSigned>
639LogicalResult MulIExtendedOpLowering<ArithMulOp, IsSigned>::matchAndRewrite(
640 ArithMulOp op,
typename ArithMulOp::Adaptor adaptor,
641 ConversionPatternRewriter &rewriter)
const {
642 Type resultType = adaptor.getLhs().getType();
647 Location loc = op.getLoc();
653 if (!isa<LLVM::LLVMArrayType>(resultType)) {
655 TypedAttr shiftValAttr;
657 if (
auto intTy = dyn_cast<IntegerType>(resultType)) {
658 unsigned resultBitwidth = intTy.getWidth();
659 auto attrTy = rewriter.getIntegerType(resultBitwidth * 2);
660 shiftValAttr = rewriter.getIntegerAttr(attrTy, resultBitwidth);
662 auto vecTy = cast<VectorType>(resultType);
663 unsigned resultBitwidth = vecTy.getElementTypeBitWidth();
664 auto attrTy = VectorType::get(
665 vecTy.getShape(), rewriter.getIntegerType(resultBitwidth * 2));
666 shiftValAttr = SplatElementsAttr::get(
667 attrTy, APInt(resultBitwidth * 2, resultBitwidth));
669 Type wideType = shiftValAttr.getType();
671 "LLVM dialect should support all signless integer types");
673 using LLVMExtOp = std::conditional_t<IsSigned, LLVM::SExtOp, LLVM::ZExtOp>;
674 Value lhsExt = LLVMExtOp::create(rewriter, loc, wideType, adaptor.getLhs());
675 Value rhsExt = LLVMExtOp::create(rewriter, loc, wideType, adaptor.getRhs());
676 Value mulExt = LLVM::MulOp::create(rewriter, loc, wideType, lhsExt, rhsExt);
679 Value low = LLVM::TruncOp::create(rewriter, loc, resultType, mulExt);
680 Value shiftVal = LLVM::ConstantOp::create(rewriter, loc, shiftValAttr);
681 Value highExt = LLVM::LShrOp::create(rewriter, loc, mulExt, shiftVal);
682 Value high = LLVM::TruncOp::create(rewriter, loc, resultType, highExt);
684 rewriter.replaceOp(op, {low, high});
688 if (!isa<VectorType>(resultType))
689 return rewriter.notifyMatchFailure(op,
"expected vector result type");
691 return rewriter.notifyMatchFailure(op,
692 "ND vector types are not supported yet");
701template <
typename LLVMPredType,
typename PredType>
703 return static_cast<LLVMPredType
>(pred);
707CmpIOpLowering::matchAndRewrite(arith::CmpIOp op, OpAdaptor adaptor,
708 ConversionPatternRewriter &rewriter)
const {
709 Type operandType = adaptor.getLhs().getType();
710 Type resultType = op.getResult().getType();
713 if (!isa<LLVM::LLVMArrayType>(operandType)) {
714 rewriter.replaceOpWithNewOp<LLVM::ICmpOp>(
715 op, typeConverter->convertType(resultType),
717 adaptor.getLhs(), adaptor.getRhs());
721 if (!isa<VectorType>(resultType))
722 return rewriter.notifyMatchFailure(op,
"expected vector result type");
725 op.getOperation(), adaptor.getOperands(), *getTypeConverter(),
726 [&](Type llvm1DVectorTy,
ValueRange operands) {
727 OpAdaptor adaptor(operands);
728 return LLVM::ICmpOp::create(
729 rewriter, op.getLoc(), llvm1DVectorTy,
731 adaptor.getLhs(), adaptor.getRhs());
741CmpFOpLowering::matchAndRewrite(arith::CmpFOp op, OpAdaptor adaptor,
742 ConversionPatternRewriter &rewriter)
const {
744 op.getLhs().getType()))
745 return rewriter.notifyMatchFailure(op,
"unsupported floating point type");
747 Type operandType = adaptor.getLhs().getType();
748 Type resultType = op.getResult().getType();
749 LLVM::FastmathFlags fmf =
750 arith::convertArithFastMathFlagsToLLVM(op.getFastmath());
753 if (!isa<LLVM::LLVMArrayType>(operandType)) {
754 rewriter.replaceOpWithNewOp<LLVM::FCmpOp>(
755 op, typeConverter->convertType(resultType),
757 adaptor.getLhs(), adaptor.getRhs(), fmf);
761 if (!isa<VectorType>(resultType))
762 return rewriter.notifyMatchFailure(op,
"expected vector result type");
765 op.getOperation(), adaptor.getOperands(), *getTypeConverter(),
766 [&](Type llvm1DVectorTy,
ValueRange operands) {
767 OpAdaptor adaptor(operands);
768 return LLVM::FCmpOp::create(
769 rewriter, op.getLoc(), llvm1DVectorTy,
771 adaptor.getLhs(), adaptor.getRhs(), fmf);
783LogicalResult SelectOpOneToNLowering::matchAndRewrite(
784 arith::SelectOp op, Adaptor adaptor,
785 ConversionPatternRewriter &rewriter)
const {
787 if (llvm::hasSingleElement(adaptor.getTrueValue()))
788 return rewriter.notifyMatchFailure(
789 op,
"not a 1:N conversion, 1:1 pattern will match");
790 if (!op.getCondition().getType().isInteger(1))
791 return rewriter.notifyMatchFailure(op,
792 "non-i1 conditions are not supported");
793 SmallVector<Value> results;
794 for (
auto [trueValue, falseValue] :
795 llvm::zip_equal(adaptor.getTrueValue(), adaptor.getFalseValue()))
796 results.push_back(arith::SelectOp::create(
797 rewriter, op.getLoc(), op.getCondition(), trueValue, falseValue));
798 rewriter.replaceOpWithMultiple(op, {results});
807struct ArithToLLVMConversionPass
808 :
public impl::ArithToLLVMConversionPassBase<ArithToLLVMConversionPass> {
811 void runOnOperation()
override {
815 const auto &dataLayoutAnalysis = getAnalysis<DataLayoutAnalysis>();
817 dataLayoutAnalysis.getAtOrAbove(getOperation()));
819 options.overrideIndexBitwidth(indexBitwidth);
822 arith::populateCeilFloorDivExpandOpsPatterns(patterns);
823 arith::populateArithToLLVMConversionPatterns(converter, patterns);
825 if (
failed(applyPartialConversion(getOperation(),
target,
826 std::move(patterns))))
838struct ArithToLLVMDialectInterface :
public ConvertToLLVMPatternInterface {
839 ArithToLLVMDialectInterface(Dialect *dialect)
840 : ConvertToLLVMPatternInterface(dialect) {}
842 void loadDependentDialects(MLIRContext *context)
const final {
843 context->loadDialect<LLVM::LLVMDialect>();
848 void populateConvertToLLVMConversionPatterns(
849 ConversionTarget &
target, LLVMTypeConverter &typeConverter,
850 RewritePatternSet &patterns)
const final {
851 arith::populateCeilFloorDivExpandOpsPatterns(patterns);
852 arith::populateArithToLLVMConversionPatterns(typeConverter, patterns);
860 dialect->addInterfaces<ArithToLLVMDialectInterface>();
873 patterns.
add<IdentityBitcastLowering>(converter, patterns.
getContext(),
879 ConstrainedAddFOpLowering,
882 AddUIExtendedOpLowering,
883 SubUIExtendedOpLowering,
889 ConstrainedDivFOpLowering,
898 IndexCastOpSILowering,
899 IndexCastOpUILowering,
902 MaximumNumFOpLowering,
907 MinimumNumFOpLowering,
911 ConstrainedMulFOpLowering,
913 MulSIExtendedOpLowering,
914 MulUIExtendedOpLowering,
921 SelectOpOneToNLowering,
927 ConstrainedSubFOpLowering,
930 ConstrainedTruncFOpLowering,