Refactor the passes name for slir lowering

This commit is contained in:
Sameer Rahmani 2021-10-06 18:48:48 +01:00
parent 2634fdb5f4
commit 10015683f5
7 changed files with 133 additions and 21 deletions

View File

@ -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)
$<$<CONFIG:DEBUG>:-fno-omit-frame-pointer>
$<$<CONFIG:RELEASE>:-fomit-frame-pointer>
$<$<CONFIG:DEBUG>:-fsanitize=address>
$<$<CONFIG:RELEASE>:-O3>
$<$<CONFIG:RELEASE>:-fmerge-all-constants>
$<$<CONFIG:RELEASE>:-flto=thin>
)
add_link_options(
# We enforce the lld linker
-fuse-ld=lld
$<$<CONFIG:RELEASE>:-fsanitize-address-globals-dead-stripping>
$<$<CONFIG:DEBUG>:-fsanitize=address>
$<$<CONFIG:RELEASE>:-flto=thin>
$<$<CONFIG:RELEASE>:-s>
# Do not link against shared libraries
#--static
)

View File

@ -80,7 +80,7 @@ function clean() {
function run() {
pushed_build
"$BUILD_DIR"/bin/serenec "$@"
"$BUILD_DIR"/src/serenec/serenec "$@"
popd_build
}

View File

@ -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:

View File

@ -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<MyFunctionPass,
OperationPass<FuncOp>> {
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<MyFunctionPass>();
}
#+END_SRC
**** OpAgnostic
#+BEGIN_SRC C++
struct MyOperationPass : public PassWrapper<MyOperationPass, OperationPass<>> {
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<MyModulePass>());
// Nest a pass manager that operates on `spirv.module` operations nested
// directly under the top-level module.
OpPassManager &nestedModulePM = pm.nest<spirv::ModuleOp>();
nestedModulePM.addPass(std::make_unique<MySPIRVModulePass>());
// Nest a pass manager that operates on functions within the nested SPIRV
// module.
OpPassManager &nestedFunctionPM = nestedModulePM.nest<FuncOp>();
nestedFunctionPM.addPass(std::make_unique<MyFunctionPass>());
// 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

View File

@ -29,7 +29,11 @@
namespace serene::passes {
std::unique_ptr<mlir::Pass> createSLIRLowerToAffinePass();
/// Return a pass to convert SLIR dialect to built-in dialects
/// of MLIR.
std::unique_ptr<mlir::Pass> createSLIRLowerToMLIRPass();
/// Return a pass to convert different dialects of MLIR to LLVM dialect.
std::unique_ptr<mlir::Pass> createSLIRLowerToLLVMDialectPass();
} // namespace serene::passes

View File

@ -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) {

View File

@ -26,7 +26,6 @@
#include "serene/slir/dialect.h"
#include <llvm/Support/Casting.h>
#include <mlir/Dialect/Affine/IR/AffineOps.h>
#include <mlir/Dialect/LLVMIR/LLVMDialect.h>
#include <mlir/Dialect/MemRef/IR/MemRef.h>
#include <mlir/Dialect/StandardOps/IR/Ops.h>
@ -102,7 +101,7 @@ FnOpLowering::matchAndRewrite(serene::slir::FnOp op,
auto attr = std::get<1>(arg).dyn_cast<mlir::TypeAttr>();
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<mlir::FuncOp>(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<mlir::ConstantIntOp>(loc, (int64_t)3, rewriter.getI64Type())
@ -125,7 +126,8 @@ FnOpLowering::matchAndRewrite(serene::slir::FnOp op,
mlir::ReturnOp returnOp = rewriter.create<mlir::ReturnOp>(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<SLIRToAffinePass,
struct SLIRToMLIRPass
: public mlir::PassWrapper<SLIRToMLIRPass,
mlir::OperationPass<mlir::ModuleOp>> {
void getDependentDialects(mlir::DialectRegistry &registry) const override;
void runOnOperation() final;
@ -147,17 +149,17 @@ struct SLIRToAffinePass
mlir::ModuleOp getModule();
};
void SLIRToAffinePass::getDependentDialects(
void SLIRToMLIRPass::getDependentDialects(
mlir::DialectRegistry &registry) const {
registry.insert<mlir::StandardOpsDialect>();
};
/// 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<mlir::Pass> createSLIRLowerToAffinePass() {
return std::make_unique<SLIRToAffinePass>();
std::unique_ptr<mlir::Pass> createSLIRLowerToMLIRPass() {
return std::make_unique<SLIRToMLIRPass>();
};
} // namespace serene::passes