From 10015683f58dcb0fb8b3ecd4b690beec8d9f1988 Mon Sep 17 00:00:00 2001 From: Sameer Rahmani Date: Wed, 6 Oct 2021 18:48:48 +0100 Subject: [PATCH] Refactor the passes name for slir lowering --- CMakeLists.txt | 10 ++- builder | 2 +- dev.org | 5 +- docs/videos.org | 99 +++++++++++++++++++++++++- include/serene/passes.h | 6 +- src/libserene/context.cpp | 2 +- src/libserene/passes/slir_lowering.cpp | 30 ++++---- 7 files changed, 133 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f95a35c..20aa6b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,7 +77,7 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) -Werror -fno-rtti -fno-builtin-strlen - -flto=thin + # Dedicate a section to each function, so the linker # can do a better job on dead code elimination -ffunction-sections @@ -92,15 +92,21 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) $<$:-fno-omit-frame-pointer> $<$:-fomit-frame-pointer> + $<$:-fsanitize=address> $<$:-O3> + $<$:-fmerge-all-constants> + $<$:-flto=thin> + ) add_link_options( # We enforce the lld linker -fuse-ld=lld + $<$:-fsanitize-address-globals-dead-stripping> $<$:-fsanitize=address> - + $<$:-flto=thin> + $<$:-s> # Do not link against shared libraries #--static ) diff --git a/builder b/builder index 91e5694..d244f88 100755 --- a/builder +++ b/builder @@ -80,7 +80,7 @@ function clean() { function run() { pushed_build - "$BUILD_DIR"/bin/serenec "$@" + "$BUILD_DIR"/src/serenec/serenec "$@" popd_build } diff --git a/dev.org b/dev.org index 127f83a..f2fab90 100644 --- a/dev.org +++ b/dev.org @@ -108,8 +108,11 @@ on ADF * TODOs ** Bootstrap* +*** TODO Create different pass pipeline for different compilation phases +So we can use them directly via command line, like -O1 for example + *** TODO Investigate the huge size of serenec -- Checkout -ffunction-sections -fdata-sections flags of lld +So far it seems that the static linking and the lack of tree shaking is the issue *** DONE Add the support for =ns-paths= :serenecli:context: CLOSED: [2021-09-25 Sat 19:22] :LOGBOOK: diff --git a/docs/videos.org b/docs/videos.org index b7be908..f76857a 100644 --- a/docs/videos.org +++ b/docs/videos.org @@ -377,7 +377,8 @@ define i64 @main1(i64 %0, i64 %1, i64 %2) !dbg !9 { - https://mlir.llvm.org/docs/LangRef - https://en.wikipedia.org/wiki/Basic_block -* Episode 9 - IR (SLIR) generation +* DONE Episode 9 - IR (SLIR) generation +CLOSED: [2021-10-01 Fri 18:56] ** Updates: - Source manager - Diagnostic Engine @@ -402,3 +403,99 @@ There will be an episode dedicated to eache of these - [X] Setup the tablegen - [X] Define the operations - [X] Walk the AST and generate the operations + +* Episode 10 - Pass Infrastructure +** The next Step +** Updates: +*** CMake changes +** What is a Pass +*** Passes are the unit of abstraction for optimization and transformation in LLVM/MLIR +*** Compilation is all about transforming the input data and produce an output + +Source code -> IR X -> IR Y -> IR Z -> ... -> Target Code + +*** Almost like a function composition +*** The big picture +*** Pass Managers (Pipelines) are made out of a collection of passes and can be nested +*** The most of the interesting parts of the compiler reside in Passes. +*** We will probably spend most of our time working with passes + +** Pass Infrastructure +*** ODS or C++ +*** Operation is the main abstract unit of transformation +*** OperationPass is the base class for all the passes. +*** We need to override =runOnOperation= +*** There's some rules you need to follow when defining your Pass +**** Must not maintain any global mutable state +**** Must not modify the state of another operation not nested within the current operation being operated on +**** ... + +*** Passes are either OpSpecific or OpAgnostic +**** OpSpecific +#+BEGIN_SRC C++ + struct MyFunctionPass : public PassWrapper> { + void runOnOperation() override { + // Get the current FuncOp operation being operated on. + FuncOp f = getOperation(); + + // Walk the operations within the function. + f.walk([](Operation *inst) { + // .... + }); + } + }; + + /// Register this pass so that it can be built via from a textual pass pipeline. + /// (Pass registration is discussed more below) + void registerMyPass() { + PassRegistration(); + } +#+END_SRC +**** OpAgnostic +#+BEGIN_SRC C++ + struct MyOperationPass : public PassWrapper> { + void runOnOperation() override { + // Get the current operation being operated on. + Operation *op = getOperation(); + // ... + } + }; +#+END_SRC +*** How transformation works? +*** Analyses and Passes +*** Pass management and nested pass managers +#+BEGIN_SRC C++ + // Create a top-level `PassManager` class. If an operation type is not + // explicitly specific, the default is the builtin `module` operation. + PassManager pm(ctx); + + // Note: We could also create the above `PassManager` this way. + PassManager pm(ctx, /*operationName=*/"builtin.module"); + + // Add a pass on the top-level module operation. + pm.addPass(std::make_unique()); + + // Nest a pass manager that operates on `spirv.module` operations nested + // directly under the top-level module. + OpPassManager &nestedModulePM = pm.nest(); + nestedModulePM.addPass(std::make_unique()); + + // Nest a pass manager that operates on functions within the nested SPIRV + // module. + OpPassManager &nestedFunctionPM = nestedModulePM.nest(); + nestedFunctionPM.addPass(std::make_unique()); + + // Run the pass manager on the top-level module. + ModuleOp m = ...; + if (failed(pm.run(m))) { + // Handle the failure + } +#+END_SRC + +* Episode 11 - Lowering SLIR +** Dialect lowering +*** Why? +*** Transforming a dialect to another dialect or LLVM IR +*** The goal is to lower SLIR to LLVM IR directly or indirectly. +** Dealing with Pass failures diff --git a/include/serene/passes.h b/include/serene/passes.h index f0d841d..77696cf 100644 --- a/include/serene/passes.h +++ b/include/serene/passes.h @@ -29,7 +29,11 @@ namespace serene::passes { -std::unique_ptr createSLIRLowerToAffinePass(); +/// Return a pass to convert SLIR dialect to built-in dialects +/// of MLIR. +std::unique_ptr createSLIRLowerToMLIRPass(); + +/// Return a pass to convert different dialects of MLIR to LLVM dialect. std::unique_ptr createSLIRLowerToLLVMDialectPass(); } // namespace serene::passes diff --git a/src/libserene/context.cpp b/src/libserene/context.cpp index 4bbb1e6..7a6f4af 100644 --- a/src/libserene/context.cpp +++ b/src/libserene/context.cpp @@ -71,7 +71,7 @@ void SereneContext::setOperationPhase(CompilationPhase phase) { } if (phase >= CompilationPhase::MLIR) { - pm.addPass(serene::passes::createSLIRLowerToAffinePass()); + pm.addPass(serene::passes::createSLIRLowerToMLIRPass()); } if (phase >= CompilationPhase::LIR) { diff --git a/src/libserene/passes/slir_lowering.cpp b/src/libserene/passes/slir_lowering.cpp index 5efac0e..f857879 100644 --- a/src/libserene/passes/slir_lowering.cpp +++ b/src/libserene/passes/slir_lowering.cpp @@ -26,7 +26,6 @@ #include "serene/slir/dialect.h" #include -#include #include #include #include @@ -102,7 +101,7 @@ FnOpLowering::matchAndRewrite(serene::slir::FnOp op, auto attr = std::get<1>(arg).dyn_cast(); if (!attr) { - llvm::outs() << "It's not a type attr\n"; + op.emitError("It's not a type attr"); return mlir::failure(); } arg_types.push_back(attr.getValue()); @@ -110,13 +109,15 @@ FnOpLowering::matchAndRewrite(serene::slir::FnOp op, auto func_type = rewriter.getFunctionType(arg_types, rewriter.getI64Type()); auto fn = rewriter.create(loc, name, func_type); + if (!fn) { - llvm::outs() << "Value Rewrite fn is null\n"; + op.emitError("Value Rewrite fn is null"); return mlir::failure(); } - auto &entryBlock = *fn.addEntryBlock(); - rewriter.setInsertionPointToStart(&entryBlock); + auto *entryBlock = fn.addEntryBlock(); + + rewriter.setInsertionPointToStart(entryBlock); auto retVal = rewriter .create(loc, (int64_t)3, rewriter.getI64Type()) @@ -125,7 +126,8 @@ FnOpLowering::matchAndRewrite(serene::slir::FnOp op, mlir::ReturnOp returnOp = rewriter.create(loc, retVal); if (!returnOp) { - llvm::outs() << "Value Rewrite returnOp is null\n"; + op.emitError("Value Rewrite returnOp is null"); + rewriter.eraseOp(fn); return mlir::failure(); } @@ -138,8 +140,8 @@ FnOpLowering::matchAndRewrite(serene::slir::FnOp op, } // SLIR lowering pass -struct SLIRToAffinePass - : public mlir::PassWrapper> { void getDependentDialects(mlir::DialectRegistry ®istry) const override; void runOnOperation() final; @@ -147,17 +149,17 @@ struct SLIRToAffinePass mlir::ModuleOp getModule(); }; -void SLIRToAffinePass::getDependentDialects( +void SLIRToMLIRPass::getDependentDialects( mlir::DialectRegistry ®istry) const { registry.insert(); }; /// Return the current function being transformed. -mlir::ModuleOp SLIRToAffinePass::getModule() { return this->getOperation(); } +mlir::ModuleOp SLIRToMLIRPass::getModule() { return this->getOperation(); } -void SLIRToAffinePass::runOnOperation() { runOnModule(); } +void SLIRToMLIRPass::runOnOperation() { runOnModule(); } -void SLIRToAffinePass::runOnModule() { +void SLIRToMLIRPass::runOnModule() { auto module = getModule(); @@ -190,7 +192,7 @@ void SLIRToAffinePass::runOnModule() { signalPassFailure(); }; -std::unique_ptr createSLIRLowerToAffinePass() { - return std::make_unique(); +std::unique_ptr createSLIRLowerToMLIRPass() { + return std::make_unique(); }; } // namespace serene::passes