Program Listing for File IndexToEmitHLS.cpp

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

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

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

#include <llvm/Support/Debug.h>
#include <mlir/Dialect/Index/IR/IndexDialect.h>

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

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

using namespace mlir;
using namespace mlir::emithls;

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

    using OpConversionPattern<index::ConstantOp>::OpConversionPattern;

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

    LogicalResult matchAndRewrite(
        index::ConstantOp op,
        index::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.getOutput().getType(),
            op.getInput());
        LAKSA_DEBUG(
            llvm::dbgs() << "Replaced " << op->getName()
                         << " with equivalent emithls operation.");
        return success();
    }
};
struct ConvertCompare : OpConversionPattern<index::CmpOp> {
    using OpConversionPattern<index::CmpOp>::OpConversionPattern;

    LogicalResult matchAndRewrite(
        index::CmpOp op,
        index::CmpOpAdaptor,
        ConversionPatternRewriter &rewriter) const override
    {
        // Create map from index predicate to emithls
        using IP = index::IndexCmpPredicate;
        using EP = emithls::CmpPredicate;
        static const DenseMap<IP, EP> predMap = {
            { IP::EQ, EP::eq},
            { IP::NE, EP::ne},
            {IP::SLT, EP::lt},
            {IP::ULT, EP::lt},
            {IP::SLE, EP::le},
            {IP::ULE, EP::le},
            {IP::SGT, EP::gt},
            {IP::UGT, EP::gt},
            {IP::SGE, EP::ge},
            {IP::UGE, EP::ge},
        };

        auto it = predMap.find(op.getPred());
        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();
    }
};
} // namespace

void mlir::populateIndexToEmitHLSConversionPatterns(
    TypeConverter &typeConverter,
    RewritePatternSet &patterns)
{
    patterns.add<ConstantVariable>(typeConverter, patterns.getContext());
    patterns.add<ConvertBinaryOp<index::AddOp, emithls::ArithAddOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<index::SubOp, emithls::ArithSubOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<index::MulOp, emithls::ArithMulOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<index::RemUOp, emithls::ArithRemOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<index::RemSOp, emithls::ArithRemOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<index::ShlOp, emithls::ArithShlOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<index::ShrUOp, emithls::ArithShrOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<index::ShrSOp, emithls::ArithShrOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<index::MaxSOp, emithls::ArithMaxOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<index::MaxUOp, emithls::ArithMaxOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<index::MinSOp, emithls::ArithMinOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<index::MinUOp, emithls::ArithMinOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<index::AndOp, emithls::ArithAndOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertBinaryOp<index::OrOp, emithls::ArithOrOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertCast<index::CastUOp, emithls::ArithCastOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertCast<index::CastSOp, emithls::ArithCastOp>>(
        typeConverter,
        patterns.getContext());
    patterns.add<ConvertCompare>(typeConverter, patterns.getContext());
}

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

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

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

    populateIndexToEmitHLSConversionPatterns(converter, patterns);

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

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

std::unique_ptr<Pass> mlir::createConvertIndexToEmitHLSPass()
{ return std::make_unique<ConvertIndexToEmitHLSPass>(); }