Add the LIR phase to lower everything to the llvm dialect

This commit is contained in:
Sameer Rahmani 2021-06-17 13:19:19 +01:00
parent ecedb14a12
commit bd4dc2301c
7 changed files with 174 additions and 31 deletions

View File

@ -41,7 +41,15 @@ using namespace serene;
namespace cl = llvm::cl;
namespace {
enum Action { None, DumpAST, DumpIR, DumpSLIR, DumpMLIR, DumpSemantic };
enum Action {
None,
DumpAST,
DumpIR,
DumpSLIR,
DumpMLIR,
DumpSemantic,
DumpLIR
};
}
static cl::opt<std::string> inputFile(cl::Positional,
@ -57,6 +65,8 @@ static cl::opt<enum Action> emitAction(
cl::values(clEnumValN(DumpSLIR, "slir", "Output the SLIR only")),
cl::values(clEnumValN(DumpMLIR, "mlir",
"Output the MLIR only (Lowered SLIR)")),
cl::values(clEnumValN(DumpLIR, "lir",
"Output the LIR only (Lowerd to LLVM dialect)")),
cl::values(clEnumValN(DumpAST, "ast", "Output the AST only"))
);
@ -117,6 +127,11 @@ int main(int argc, char *argv[]) {
break;
}
case Action::DumpLIR: {
ctx->setOperationPhase(CompilationPhase::LIR);
break;
}
default: {
llvm::errs() << "No action specified. TODO: Print out help here\n";
return 1;

View File

@ -27,7 +27,7 @@
#include "serene/environment.h"
#include "serene/namespace.h"
#include "serene/passes/slir_lowering.h"
#include "serene/passes.h"
#include "serene/slir/dialect.h"
#include <llvm/ADT/StringRef.h>
@ -42,7 +42,13 @@ class Expression;
using Node = std::shared_ptr<Expression>;
} // namespace exprs
enum class CompilationPhase { SLIR, MLIR, IR, O1 };
enum class CompilationPhase {
SLIR,
MLIR, // Lowered slir to other dialects
LIR, // Lowered to the llvm ir dialect
IR, // Lowered to the LLVMIR itself
O1
};
class SereneContext {
std::map<std::string, std::shared_ptr<Namespace>> namespaces;

View File

@ -21,34 +21,17 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "mlir/Dialect/StandardOps/IR/Ops.h"
#include "serene/slir/dialect.h"
#include <mlir/Dialect/Affine/IR/AffineOps.h>
#include <mlir/Dialect/LLVMIR/LLVMDialect.h>
#include <mlir/Dialect/MemRef/IR/MemRef.h>
#include <mlir/IR/BuiltinOps.h>
#ifndef SERENE_PASSES_H
#define SERENE_PASSES_H
#include <mlir/Pass/Pass.h>
#include <mlir/Transforms/DialectConversion.h>
namespace serene::passes {
struct ValueOpLowering : public mlir::OpRewritePattern<serene::slir::ValueOp> {
using OpRewritePattern<serene::slir::ValueOp>::OpRewritePattern;
mlir::LogicalResult
matchAndRewrite(serene::slir::ValueOp op,
mlir::PatternRewriter &rewriter) const final;
};
struct SLIRToAffinePass
: public mlir::PassWrapper<SLIRToAffinePass,
mlir::OperationPass<mlir::ModuleOp>> {
void getDependentDialects(mlir::DialectRegistry &registry) const override;
void runOnOperation() final;
void runOnModule();
mlir::ModuleOp getModule();
};
std::unique_ptr<mlir::Pass> createSLIRLowerToAffinePass();
std::unique_ptr<mlir::Pass> createSLIRLowerToLLVMDialectPass();
} // namespace serene::passes
#endif

View File

@ -34,7 +34,7 @@ set(HEADER_LIST
"${INCLUDE_DIR}/serene/slir/utils.h"
"${INCLUDE_DIR}/serene/namespace.h"
"${INCLUDE_DIR}/serene/passes/slir_lowering.h")
"${INCLUDE_DIR}/serene/passes.h")
# Make an automatic library - will be static or dynamic based on user setting
add_library(serene
@ -67,6 +67,7 @@ add_library(serene
slir/utils.cpp
passes/slir_lowering.cpp
passes/to_llvm_dialect.cpp
${HEADER_LIST})
@ -85,7 +86,26 @@ endif()
target_include_directories(serene PRIVATE ${INCLUDE_DIR})
target_include_directories(serene PUBLIC ${PROJECT_BINARY_DIR})
# This depends on (header only) boost
target_link_libraries(serene ${llvm_libs})
source_group(TREE "${INCLUDE_DIR}" PREFIX "Header Files" FILES ${HEADER_LIST})
#target_precompile_headers(serene PRIVATE ${HEADER_LIST})
get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
get_property(conversion_libs GLOBAL PROPERTY MLIR_CONVERSION_LIBS)
# This depends on (header only) boost
target_link_libraries(serene
PRIVATE
${dialect_libs}
${conversion_libs}
MLIRAnalysis
MLIRCallInterfaces
MLIRCastInterfaces
MLIRExecutionEngine
MLIRIR
MLIRLLVMToLLVMIRTranslation
MLIRParser
MLIRPass
MLIRSideEffectInterfaces
MLIRTargetLLVMIRExport
MLIRTransforms
${llvm_libs}
)

View File

@ -25,6 +25,7 @@
#include "serene/context.h"
#include "serene/namespace.h"
#include "serene/passes.h"
namespace serene {
@ -64,9 +65,13 @@ void SereneContext::setOperationPhase(CompilationPhase phase) {
return;
}
if (phase == CompilationPhase::MLIR) {
if (phase >= CompilationPhase::MLIR) {
pm.addPass(serene::passes::createSLIRLowerToAffinePass());
}
if (phase >= CompilationPhase::LIR) {
pm.addPass(serene::passes::createSLIRLowerToLLVMDialectPass());
}
};
std::unique_ptr<SereneContext> makeSereneContext() {

View File

@ -22,12 +22,27 @@
* SOFTWARE.
*/
#include "serene/passes/slir_lowering.h"
#include "mlir/Dialect/StandardOps/IR/Ops.h"
#include "serene/passes.h"
#include "serene/slir/dialect.h"
#include <mlir/Dialect/Affine/IR/AffineOps.h>
#include <mlir/Dialect/LLVMIR/LLVMDialect.h>
#include <mlir/Dialect/MemRef/IR/MemRef.h>
#include <mlir/IR/BuiltinOps.h>
#include <mlir/Pass/Pass.h>
#include <mlir/Transforms/DialectConversion.h>
namespace serene::passes {
struct ValueOpLowering : public mlir::OpRewritePattern<serene::slir::ValueOp> {
using OpRewritePattern<serene::slir::ValueOp>::OpRewritePattern;
mlir::LogicalResult
matchAndRewrite(serene::slir::ValueOp op,
mlir::PatternRewriter &rewriter) const final;
};
mlir::LogicalResult
ValueOpLowering::matchAndRewrite(serene::slir::ValueOp op,
mlir::PatternRewriter &rewriter) const {
@ -44,6 +59,15 @@ ValueOpLowering::matchAndRewrite(serene::slir::ValueOp op,
return mlir::success();
}
struct SLIRToAffinePass
: public mlir::PassWrapper<SLIRToAffinePass,
mlir::OperationPass<mlir::ModuleOp>> {
void getDependentDialects(mlir::DialectRegistry &registry) const override;
void runOnOperation() final;
void runOnModule();
mlir::ModuleOp getModule();
};
void SLIRToAffinePass::getDependentDialects(
mlir::DialectRegistry &registry) const {
registry.insert<mlir::AffineDialect, mlir::memref::MemRefDialect,

View File

@ -0,0 +1,90 @@
/* -*- C++ -*-
* Serene programming language.
*
* Copyright (c) 2019-2021 Sameer Rahmani <lxsameer@gnu.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "serene/passes.h"
#include "serene/slir/dialect.h"
#include <memory>
#include <mlir/Conversion/AffineToStandard/AffineToStandard.h>
#include <mlir/Conversion/SCFToStandard/SCFToStandard.h>
#include <mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h>
#include <mlir/Conversion/StandardToLLVM/ConvertStandardToLLVMPass.h>
#include <mlir/Dialect/LLVMIR/LLVMDialect.h>
#include <mlir/Dialect/SCF/SCF.h>
#include <mlir/IR/BuiltinOps.h>
#include <mlir/Pass/Pass.h>
#include <mlir/Transforms/DialectConversion.h>
namespace serene::passes {
struct SLIRToLLVMDialect
: public mlir::PassWrapper<SLIRToLLVMDialect,
mlir::OperationPass<mlir::ModuleOp>> {
void getDependentDialects(mlir::DialectRegistry &registry) const override {
registry.insert<mlir::LLVM::LLVMDialect, mlir::scf::SCFDialect>();
}
void runOnOperation() final;
};
void SLIRToLLVMDialect::runOnOperation() {
// The first thing to define is the conversion target. This will define the
// final target for this lowering. For this lowering, we are only targeting
// the LLVM dialect.
mlir::LLVMConversionTarget target(getContext());
target.addLegalOp<mlir::ModuleOp>();
// During this lowering, we will also be lowering the MemRef types, that are
// currently being operated on, to a representation in LLVM. To perform this
// conversion we use a TypeConverter as part of the lowering. This converter
// details how one type maps to another. This is necessary now that we will be
// doing more complicated lowerings, involving loop region arguments.
mlir::LLVMTypeConverter typeConverter(&getContext());
// Now that the conversion target has been defined, we need to provide the
// patterns used for lowering. At this point of the compilation process, we
// have a combination of `toy`, `affine`, and `std` operations. Luckily, there
// are already exists a set of patterns to transform `affine` and `std`
// dialects. These patterns lowering in multiple stages, relying on transitive
// lowerings. Transitive lowering, or A->B->C lowering, is when multiple
// patterns must be applied to fully transform an illegal operation into a
// set of legal ones.
mlir::RewritePatternSet patterns(&getContext());
mlir::populateAffineToStdConversionPatterns(patterns);
populateLoopToStdConversionPatterns(patterns);
populateStdToLLVMConversionPatterns(typeConverter, patterns);
// patterns.add<PrintOpLowering>(&getContext());
// We want to completely lower to LLVM, so we use a `FullConversion`. This
// ensures that only legal operations will remain after the conversion.
auto module = getOperation();
if (failed(applyFullConversion(module, target, std::move(patterns))))
signalPassFailure();
};
std::unique_ptr<mlir::Pass> createSLIRLowerToLLVMDialectPass() {
return std::make_unique<SLIRToLLVMDialect>();
};
} // namespace serene::passes