Refactor the passes name for slir lowering
This commit is contained in:
parent
2634fdb5f4
commit
10015683f5
|
@ -77,7 +77,7 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
|
||||||
-Werror
|
-Werror
|
||||||
-fno-rtti
|
-fno-rtti
|
||||||
-fno-builtin-strlen
|
-fno-builtin-strlen
|
||||||
-flto=thin
|
|
||||||
# Dedicate a section to each function, so the linker
|
# Dedicate a section to each function, so the linker
|
||||||
# can do a better job on dead code elimination
|
# can do a better job on dead code elimination
|
||||||
-ffunction-sections
|
-ffunction-sections
|
||||||
|
@ -92,15 +92,21 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
|
||||||
|
|
||||||
$<$<CONFIG:DEBUG>:-fno-omit-frame-pointer>
|
$<$<CONFIG:DEBUG>:-fno-omit-frame-pointer>
|
||||||
$<$<CONFIG:RELEASE>:-fomit-frame-pointer>
|
$<$<CONFIG:RELEASE>:-fomit-frame-pointer>
|
||||||
|
$<$<CONFIG:DEBUG>:-fsanitize=address>
|
||||||
|
|
||||||
$<$<CONFIG:RELEASE>:-O3>
|
$<$<CONFIG:RELEASE>:-O3>
|
||||||
|
$<$<CONFIG:RELEASE>:-fmerge-all-constants>
|
||||||
|
$<$<CONFIG:RELEASE>:-flto=thin>
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
add_link_options(
|
add_link_options(
|
||||||
# We enforce the lld linker
|
# We enforce the lld linker
|
||||||
-fuse-ld=lld
|
-fuse-ld=lld
|
||||||
|
$<$<CONFIG:RELEASE>:-fsanitize-address-globals-dead-stripping>
|
||||||
$<$<CONFIG:DEBUG>:-fsanitize=address>
|
$<$<CONFIG:DEBUG>:-fsanitize=address>
|
||||||
|
$<$<CONFIG:RELEASE>:-flto=thin>
|
||||||
|
$<$<CONFIG:RELEASE>:-s>
|
||||||
# Do not link against shared libraries
|
# Do not link against shared libraries
|
||||||
#--static
|
#--static
|
||||||
)
|
)
|
||||||
|
|
2
builder
2
builder
|
@ -80,7 +80,7 @@ function clean() {
|
||||||
|
|
||||||
function run() {
|
function run() {
|
||||||
pushed_build
|
pushed_build
|
||||||
"$BUILD_DIR"/bin/serenec "$@"
|
"$BUILD_DIR"/src/serenec/serenec "$@"
|
||||||
popd_build
|
popd_build
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
5
dev.org
5
dev.org
|
@ -108,8 +108,11 @@ on ADF
|
||||||
|
|
||||||
* TODOs
|
* TODOs
|
||||||
** Bootstrap*
|
** 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
|
*** 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:
|
*** DONE Add the support for =ns-paths= :serenecli:context:
|
||||||
CLOSED: [2021-09-25 Sat 19:22]
|
CLOSED: [2021-09-25 Sat 19:22]
|
||||||
:LOGBOOK:
|
:LOGBOOK:
|
||||||
|
|
|
@ -377,7 +377,8 @@ define i64 @main1(i64 %0, i64 %1, i64 %2) !dbg !9 {
|
||||||
- https://mlir.llvm.org/docs/LangRef
|
- https://mlir.llvm.org/docs/LangRef
|
||||||
- https://en.wikipedia.org/wiki/Basic_block
|
- 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:
|
** Updates:
|
||||||
- Source manager
|
- Source manager
|
||||||
- Diagnostic Engine
|
- Diagnostic Engine
|
||||||
|
@ -402,3 +403,99 @@ There will be an episode dedicated to eache of these
|
||||||
- [X] Setup the tablegen
|
- [X] Setup the tablegen
|
||||||
- [X] Define the operations
|
- [X] Define the operations
|
||||||
- [X] Walk the AST and generate 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
|
||||||
|
|
|
@ -29,7 +29,11 @@
|
||||||
|
|
||||||
namespace serene::passes {
|
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();
|
std::unique_ptr<mlir::Pass> createSLIRLowerToLLVMDialectPass();
|
||||||
|
|
||||||
} // namespace serene::passes
|
} // namespace serene::passes
|
||||||
|
|
|
@ -71,7 +71,7 @@ void SereneContext::setOperationPhase(CompilationPhase phase) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (phase >= CompilationPhase::MLIR) {
|
if (phase >= CompilationPhase::MLIR) {
|
||||||
pm.addPass(serene::passes::createSLIRLowerToAffinePass());
|
pm.addPass(serene::passes::createSLIRLowerToMLIRPass());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (phase >= CompilationPhase::LIR) {
|
if (phase >= CompilationPhase::LIR) {
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
#include "serene/slir/dialect.h"
|
#include "serene/slir/dialect.h"
|
||||||
|
|
||||||
#include <llvm/Support/Casting.h>
|
#include <llvm/Support/Casting.h>
|
||||||
#include <mlir/Dialect/Affine/IR/AffineOps.h>
|
|
||||||
#include <mlir/Dialect/LLVMIR/LLVMDialect.h>
|
#include <mlir/Dialect/LLVMIR/LLVMDialect.h>
|
||||||
#include <mlir/Dialect/MemRef/IR/MemRef.h>
|
#include <mlir/Dialect/MemRef/IR/MemRef.h>
|
||||||
#include <mlir/Dialect/StandardOps/IR/Ops.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>();
|
auto attr = std::get<1>(arg).dyn_cast<mlir::TypeAttr>();
|
||||||
|
|
||||||
if (!attr) {
|
if (!attr) {
|
||||||
llvm::outs() << "It's not a type attr\n";
|
op.emitError("It's not a type attr");
|
||||||
return mlir::failure();
|
return mlir::failure();
|
||||||
}
|
}
|
||||||
arg_types.push_back(attr.getValue());
|
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 func_type = rewriter.getFunctionType(arg_types, rewriter.getI64Type());
|
||||||
auto fn = rewriter.create<mlir::FuncOp>(loc, name, func_type);
|
auto fn = rewriter.create<mlir::FuncOp>(loc, name, func_type);
|
||||||
|
|
||||||
if (!fn) {
|
if (!fn) {
|
||||||
llvm::outs() << "Value Rewrite fn is null\n";
|
op.emitError("Value Rewrite fn is null");
|
||||||
return mlir::failure();
|
return mlir::failure();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &entryBlock = *fn.addEntryBlock();
|
auto *entryBlock = fn.addEntryBlock();
|
||||||
rewriter.setInsertionPointToStart(&entryBlock);
|
|
||||||
|
rewriter.setInsertionPointToStart(entryBlock);
|
||||||
auto retVal =
|
auto retVal =
|
||||||
rewriter
|
rewriter
|
||||||
.create<mlir::ConstantIntOp>(loc, (int64_t)3, rewriter.getI64Type())
|
.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);
|
mlir::ReturnOp returnOp = rewriter.create<mlir::ReturnOp>(loc, retVal);
|
||||||
|
|
||||||
if (!returnOp) {
|
if (!returnOp) {
|
||||||
llvm::outs() << "Value Rewrite returnOp is null\n";
|
op.emitError("Value Rewrite returnOp is null");
|
||||||
|
rewriter.eraseOp(fn);
|
||||||
return mlir::failure();
|
return mlir::failure();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,8 +140,8 @@ FnOpLowering::matchAndRewrite(serene::slir::FnOp op,
|
||||||
}
|
}
|
||||||
|
|
||||||
// SLIR lowering pass
|
// SLIR lowering pass
|
||||||
struct SLIRToAffinePass
|
struct SLIRToMLIRPass
|
||||||
: public mlir::PassWrapper<SLIRToAffinePass,
|
: public mlir::PassWrapper<SLIRToMLIRPass,
|
||||||
mlir::OperationPass<mlir::ModuleOp>> {
|
mlir::OperationPass<mlir::ModuleOp>> {
|
||||||
void getDependentDialects(mlir::DialectRegistry ®istry) const override;
|
void getDependentDialects(mlir::DialectRegistry ®istry) const override;
|
||||||
void runOnOperation() final;
|
void runOnOperation() final;
|
||||||
|
@ -147,17 +149,17 @@ struct SLIRToAffinePass
|
||||||
mlir::ModuleOp getModule();
|
mlir::ModuleOp getModule();
|
||||||
};
|
};
|
||||||
|
|
||||||
void SLIRToAffinePass::getDependentDialects(
|
void SLIRToMLIRPass::getDependentDialects(
|
||||||
mlir::DialectRegistry ®istry) const {
|
mlir::DialectRegistry ®istry) const {
|
||||||
registry.insert<mlir::StandardOpsDialect>();
|
registry.insert<mlir::StandardOpsDialect>();
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Return the current function being transformed.
|
/// 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();
|
auto module = getModule();
|
||||||
|
|
||||||
|
@ -190,7 +192,7 @@ void SLIRToAffinePass::runOnModule() {
|
||||||
signalPassFailure();
|
signalPassFailure();
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<mlir::Pass> createSLIRLowerToAffinePass() {
|
std::unique_ptr<mlir::Pass> createSLIRLowerToMLIRPass() {
|
||||||
return std::make_unique<SLIRToAffinePass>();
|
return std::make_unique<SLIRToMLIRPass>();
|
||||||
};
|
};
|
||||||
} // namespace serene::passes
|
} // namespace serene::passes
|
||||||
|
|
Loading…
Reference in New Issue