Program Listing for File ArithToEmitHLS.cpp

↰ Return to documentation for file (lib/Conversion/ArithToEmitHLS/ArithToEmitHLS.cpp)

#include "laksa-mlir/Conversion/ArithToEmitHLS/ArithToEmitHLS.h"

#include "laksa-mlir/Dialect/EmitHLS/IR/EmitHLS.h"
#include "laksa-mlir/Dialect/EmitHLS/IR/EmitHLSOps.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/IR/PatternMatch.h"

#include <llvm/Support/Debug.h>

#define DEBUG_TYPE "arith-to-emithls"
#define LAKSA_DEBUG(X)                                                         \
    LLVM_DEBUG(llvm::dbgs() << "[arith-to-emithls] "; X; llvm::dbgs() << "\n")

namespace mlir {
#define GEN_PASS_DEF_CONVERTARITHTOEMITHLS
#include "laksa-mlir/Conversion/Passes.h.inc"
} // namespace mlir

using namespace mlir;
using namespace mlir::emithls;

namespace {
struct ConstantVariable : OpConversionPattern<arith::ConstantOp> {

    using OpConversionPattern<arith::ConstantOp>::OpConversionPattern;

    ConstantVariable(TypeConverter &typeConverter, MLIRContext* context)
            : OpConversionPattern<arith::ConstantOp>(typeConverter, context) {};

    LogicalResult matchAndRewrite(
        arith::ConstantOp op,
        arith::ConstantOpAdaptor,
        ConversionPatternRewriter &rewriter) const override
    {
        rewriter.replaceOpWithNewOp<emithls::VariableOp>(
            op,
            op.getType(),
            /*init*/ op.getValueAttr(),
            /*is_const*/ true);
        LAKSA_DEBUG(
            llvm::dbgs() << "Replaced constant with a constant variable.");
        return success();
    }
};
template<typename OpFrom, typename OpTo>
struct ConvertBinaryOp : OpConversionPattern<OpFrom> {
    using OpConversionPattern<OpFrom>::OpConversionPattern;

    ConvertBinaryOp(TypeConverter &typeConverter, MLIRContext* context)
            : OpConversionPattern<OpFrom>(typeConverter, context) {};

    LogicalResult matchAndRewrite(
        OpFrom op,
        typename OpFrom::Adaptor,
        ConversionPatternRewriter &rewriter) const override
    {
        rewriter.replaceOpWithNewOp<OpTo>(op, op.getLhs(), op.getRhs());
        LAKSA_DEBUG(
            llvm::dbgs() << "Replaced " << op->getName()
                         << " with equivalent emithls operation.");
        return success();
    }
};
template<typename OpFrom, typename OpTo>
struct ConvertCast : OpConversionPattern<OpFrom> {
    using OpConversionPattern<OpFrom>::OpConversionPattern;

    ConvertCast(TypeConverter &typeConverter, MLIRContext* context)
            : OpConversionPattern<OpFrom>(typeConverter, context) {};

    LogicalResult matchAndRewrite(
        OpFrom op,
        typename OpFrom::Adaptor,
        ConversionPatternRewriter &rewriter) const override
    {
        rewriter.replaceOpWithNewOp<OpTo>(
            op,
            op.getOut().getType(),
            op.getIn());
        LAKSA_DEBUG(
            llvm::dbgs() << "Replaced " << op->getName()
                         << " with equivalent emithls operation.");
        return success();
    }
};
struct ConvertCompare : OpConversionPattern<arith::CmpIOp> {
    using OpConversionPattern<arith::CmpIOp>::OpConversionPattern;

    LogicalResult matchAndRewrite(
        arith::CmpIOp op,
        arith::CmpIOpAdaptor,
        ConversionPatternRewriter &rewriter) const override
    {
        // Create map from arith predicate to emithls
        using AP = arith::CmpIPredicate;
        using EP = emithls::CmpPredicate;
        static const DenseMap<AP, EP> predMap = {
            { AP::eq, EP::eq},
            { AP::ne, EP::ne},
            {AP::slt, EP::lt},
            {AP::ult, EP::lt},
            {AP::sle, EP::le},
            {AP::ule, EP::le},
            {AP::sgt, EP::gt},
            {AP::ugt, EP::gt},
            {AP::sge, EP::ge},
            {AP::uge, EP::ge},
        };

        auto it = predMap.find(op.getPredicate());
        if (it == predMap.end())
            return rewriter.notifyMatchFailure(op, "unsupported predicate");
        rewriter.replaceOpWithNewOp<ArithCmpOp>(
            op,
            it->second,
            op.getLhs(),
            op.getRhs());
        LAKSA_DEBUG(
            llvm::dbgs()
            << "Replaced compare operation with equivalent emithls operation.");
        return success();
    }
};
struct ConvertSelect : OpConversionPattern<arith::SelectOp> {
    using OpConversionPattern<arith::SelectOp>::OpConversionPattern;

    ConvertSelect(TypeConverter &typeConverter, MLIRContext* context)
            : OpConversionPattern<arith::SelectOp>(typeConverter, context) {};

    LogicalResult matchAndRewrite(
        arith::SelectOp op,
        arith::SelectOpAdaptor,
        ConversionPatternRewriter &rewriter) const override
    {
        rewriter.replaceOpWithNewOp<emithls::ArithSelectOp>(
            op,
            op.getCondition(),
            op.getTrueValue(),
            op.getFalseValue());
        LAKSA_DEBUG(
            llvm::dbgs()
            << "Replaced select operation with equivalent emithls operation.");
        return success();
    }
};
} // namespace

void mlir::populateArithToEmitHLSConversionPatterns(
    TypeConverter &typeConverter,
    RewritePatternSet &patterns)
{
    patterns.add<ConstantVariable>(typeConverter, patterns.getContext());
    patterns.add<ConvertBinaryOp<arith::AddIOp, emithls::ArithAddOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<arith::SubIOp, emithls::ArithSubOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<arith::MulIOp, emithls::ArithMulOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<arith::RemUIOp, emithls::ArithRemOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<arith::RemSIOp, emithls::ArithRemOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<arith::ShLIOp, emithls::ArithShlOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<arith::ShRUIOp, emithls::ArithShrOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<arith::ShRSIOp, emithls::ArithShrOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<arith::MaxSIOp, emithls::ArithMaxOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<arith::MaxUIOp, emithls::ArithMaxOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<arith::MinSIOp, emithls::ArithMinOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<arith::MinUIOp, emithls::ArithMinOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<arith::AndIOp, emithls::ArithAndOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<arith::OrIOp, emithls::ArithOrOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertCast<arith::IndexCastOp, emithls::ArithCastOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertCast<arith::IndexCastUIOp, emithls::ArithCastOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertCast<arith::ExtSIOp, emithls::ArithCastOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertCast<arith::ExtUIOp, emithls::ArithCastOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertCast<arith::TruncIOp, emithls::ArithCastOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertCompare>(typeConverter, patterns.getContext());
    patterns.add<ConvertSelect>(typeConverter, patterns.getContext());
}

namespace {
struct ConvertArithToEmitHLSPass
        : public impl::ConvertArithToEmitHLSBase<ConvertArithToEmitHLSPass> {
    void runOnOperation() final;
};
} // namespace

void ConvertArithToEmitHLSPass::runOnOperation()
{
    ConversionTarget target(getContext());
    RewritePatternSet patterns(&getContext());

    TypeConverter converter;
    converter.addConversion([&](Type type) { return type; });

    populateArithToEmitHLSConversionPatterns(converter, patterns);

    target.addLegalDialect<EmitHLSDialect>();
    target.addIllegalDialect<arith::ArithDialect>();
    target.markUnknownOpDynamicallyLegal([](Operation*) { return true; });

    if (failed(applyPartialConversion(
            getOperation(),
            target,
            std::move(patterns)))) {
        signalPassFailure();
    }
}

std::unique_ptr<Pass> mlir::createConvertArithToEmitHLSPass()
{ return std::make_unique<ConvertArithToEmitHLSPass>(); }