diff --git a/bin/serene.cpp b/bin/serene.cpp index 1a5a1b3..bfaf86f 100644 --- a/bin/serene.cpp +++ b/bin/serene.cpp @@ -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 inputFile(cl::Positional, @@ -57,6 +65,8 @@ static cl::opt 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; diff --git a/include/serene/context.h b/include/serene/context.h index 7bcbbaa..9c8b166 100644 --- a/include/serene/context.h +++ b/include/serene/context.h @@ -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 @@ -42,7 +42,13 @@ class Expression; using Node = std::shared_ptr; } // 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> namespaces; diff --git a/include/serene/passes/slir_lowering.h b/include/serene/passes.h similarity index 60% rename from include/serene/passes/slir_lowering.h rename to include/serene/passes.h index 5428e70..f0d841d 100644 --- a/include/serene/passes/slir_lowering.h +++ b/include/serene/passes.h @@ -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 -#include -#include -#include +#ifndef SERENE_PASSES_H +#define SERENE_PASSES_H + #include -#include namespace serene::passes { -struct ValueOpLowering : public mlir::OpRewritePattern { - using OpRewritePattern::OpRewritePattern; - - mlir::LogicalResult - matchAndRewrite(serene::slir::ValueOp op, - mlir::PatternRewriter &rewriter) const final; -}; - -struct SLIRToAffinePass - : public mlir::PassWrapper> { - void getDependentDialects(mlir::DialectRegistry ®istry) const override; - void runOnOperation() final; - void runOnModule(); - mlir::ModuleOp getModule(); -}; std::unique_ptr createSLIRLowerToAffinePass(); +std::unique_ptr createSLIRLowerToLLVMDialectPass(); } // namespace serene::passes + +#endif diff --git a/src/serene/CMakeLists.txt b/src/serene/CMakeLists.txt index 7961322..cecf977 100644 --- a/src/serene/CMakeLists.txt +++ b/src/serene/CMakeLists.txt @@ -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} + ) diff --git a/src/serene/context.cpp b/src/serene/context.cpp index e0fc63d..5a21a86 100644 --- a/src/serene/context.cpp +++ b/src/serene/context.cpp @@ -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 makeSereneContext() { diff --git a/src/serene/passes/slir_lowering.cpp b/src/serene/passes/slir_lowering.cpp index 2bf05ee..00120e5 100644 --- a/src/serene/passes/slir_lowering.cpp +++ b/src/serene/passes/slir_lowering.cpp @@ -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 +#include +#include #include +#include +#include namespace serene::passes { +struct ValueOpLowering : public mlir::OpRewritePattern { + using OpRewritePattern::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> { + void getDependentDialects(mlir::DialectRegistry ®istry) const override; + void runOnOperation() final; + void runOnModule(); + mlir::ModuleOp getModule(); +}; + void SLIRToAffinePass::getDependentDialects( mlir::DialectRegistry ®istry) const { registry.insert + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace serene::passes { +struct SLIRToLLVMDialect + : public mlir::PassWrapper> { + void getDependentDialects(mlir::DialectRegistry ®istry) const override { + registry.insert(); + } + + 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(); + + // 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(&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 createSLIRLowerToLLVMDialectPass() { + return std::make_unique(); +}; + +} // namespace serene::passes