|
| 1 | +.. _mlir-getting-started |
| 2 | +
|
| 3 | +=============== |
| 4 | +Getting started |
| 5 | +=============== |
| 6 | + |
| 7 | +Build |
| 8 | +----- |
| 9 | +Build `era-compiler-llvm <https://github.com/matter-labs/era-compiler-llvm>`_ |
| 10 | +checked out at branch ``app-mlir`` with mlir and lld projects enabled. Make sure |
| 11 | +rtti is on: |
| 12 | + |
| 13 | + .. code-block:: bash |
| 14 | +
|
| 15 | + cmake <llvm> \ |
| 16 | + ... |
| 17 | + '-DLLVM_ENABLE_PROJECTS=mlir;lld' \ |
| 18 | + '-DLLVM_ENABLE_RTTI=ON' \ |
| 19 | +
|
| 20 | + ninja or make or ... |
| 21 | +
|
| 22 | +
|
| 23 | +Then build this project using: |
| 24 | + |
| 25 | + |
| 26 | + .. code-block:: bash |
| 27 | +
|
| 28 | + cmake <solidity> \ |
| 29 | + ... |
| 30 | + '-DMLIR_DIR=<llvm-build>/lib/cmake/mlir' \ |
| 31 | + '-DLLD_DIR=<llvm-build>/lib/cmake/lld' |
| 32 | + # Where <llvm-build> is the *absolute* path to the llvm build. |
| 33 | +
|
| 34 | + ninja or make or ... |
| 35 | +
|
| 36 | +Style |
| 37 | +----- |
| 38 | +- More or less `mlir style guide |
| 39 | + <https://mlir.llvm.org/getting_started/DeveloperGuide/#style-guide>`_, which |
| 40 | + is the llvm style with some modification like using camelBack, no const |
| 41 | + correctness (`see <https://mlir.llvm.org/docs/Rationale/UsageOfConst>`_) etc. |
| 42 | + |
| 43 | +- Some quirks I personally found helpful: Builder instances are named ``b`` and |
| 44 | + Rewriter instances are named ``r``. This makes the ir building/rewriting code |
| 45 | + look a little more concise and cleaner where the intent like "create an op", |
| 46 | + "replace an op" is more clearer. This is a little like llvm's ``IRBuilder`` |
| 47 | + instances named as "irb". |
| 48 | + |
| 49 | +- Tests are written to be as minimal as possible. No licenses, unnecessary |
| 50 | + specifiers (like pure) that doesn't affect the lowering etc., and the code |
| 51 | + might not make sense. The focus is purely on the behaviour of the codegen, |
| 52 | + with maximum coverage. A bit of a duh, but when you fix a bug, always add a |
| 53 | + minimal reproducer test! |
| 54 | + |
| 55 | +- Location tracking is (``--mmlir --mlir-print-debuginfo``) mandatory in every |
| 56 | + source (non-mlir) FileCheck tests. |
| 57 | + |
| 58 | +- Like in llvm, assert liberally. Unimplemented sections should assert-fail with |
| 59 | + an "NYI" ("Not yet implemented") message. |
| 60 | + |
| 61 | +Before committing |
| 62 | +----------------- |
| 63 | +Once a patch is ready, you should do the following: |
| 64 | + |
| 65 | +1. Testing |
| 66 | +~~~~~~~~~~ |
| 67 | +- Run ``test/updFileCheckTest.py`` on each FileCheck test files under |
| 68 | + ``test/lit/mlirCodegen`` and check if the updates are correct. I do something |
| 69 | + like this to update all tests in parallel: |
| 70 | + |
| 71 | + .. code-block:: bash |
| 72 | +
|
| 73 | + find test/lit/mlirCodegen -type f \( -name '*.sol' -o -name '*.yul' \) \ |
| 74 | + | xargs -n1 -P$(nproc) \ |
| 75 | + test/updFileCheckTest.py --path "<solc-build>/solc" |
| 76 | +
|
| 77 | + find test/lit/mlirCodegen -type f -name '*.mlir' \ |
| 78 | + | xargs -n1 -P$(nproc) \ |
| 79 | + test/updFileCheckTest.py --path "<solc-build>/tools/solOpt" |
| 80 | +
|
| 81 | +- Run the build rule ``check-solidity-mlir`` to run the lit test suite (and make |
| 82 | + sure it passes, duh). |
| 83 | + |
| 84 | +- Run semantic tests using soltest. For this you need to build `evmone |
| 85 | + <https://github.com/ethereum/evmone>`_ using simple cmake, nothing fancy, |
| 86 | + which will build the ``libevmone.so`` used for the semantic testing. Then run: |
| 87 | + |
| 88 | + .. code-block:: bash |
| 89 | +
|
| 90 | + soltest -t semanticTests/mlir -- --testpath <test-path> --vm <libevmone.so-path>. |
| 91 | +
|
| 92 | + Where ``<test-path>`` is ``<solc-root>/test``. Note that "semanticTests/mlir" |
| 93 | + is a filter. You can restrict to, say, one test with ``-t |
| 94 | + semanticTests/mlir/<file>`` |
| 95 | + |
| 96 | +2. Add tests |
| 97 | +~~~~~~~~~~~~ |
| 98 | +- Add a new test under ``test/lit/mlirCodegen`` that tests your change. Follow |
| 99 | + the existing formats of adding both a high level dialect test and standard |
| 100 | + dialect test. It's better to generate the check-lines using |
| 101 | + ``updFileCheckTest.py`` as our mlir dialect representations are not fully |
| 102 | + stable yet. |
| 103 | + |
| 104 | + (We don’t test dialects/ir/asm below the standard dialects - the lowering |
| 105 | + chain beneath them is already covered by llvm and mlir test suites. But we do |
| 106 | + keep one or two full-lowering smoke tests around for good measure.) |
| 107 | + |
| 108 | +- If possible, add a semantic test under ``test/libsolidity/semanticTests/mlir`` |
| 109 | + following the format of other tests there. |
| 110 | + |
| 111 | +3. Linting |
| 112 | +~~~~~~~~~~ |
| 113 | +- Once all the tests pass, if possible, fix all compiler warnings. |
| 114 | + |
| 115 | +- clang-format your changes using something like: |
| 116 | + |
| 117 | + .. code-block:: bash |
| 118 | +
|
| 119 | + git clang-format |
| 120 | +
|
| 121 | + Don’t run clang-format on upstream solc files! Follow the surrounding style |
| 122 | + instead - afaik, upstream solc doesn't use auto-formatters. |
| 123 | + |
| 124 | +- Then, optionally, run clang-tidy on your changes. I just run this: |
| 125 | + |
| 126 | + .. code-block:: bash |
| 127 | +
|
| 128 | + find libsolidity/codegen/mlir -name '*.cpp' \ |
| 129 | + | xargs -n1 -P"$(nproc)" clang-tidy -p <build-path> |
| 130 | +
|
| 131 | +Intro to the codegen |
| 132 | +-------------------- |
| 133 | +``libsolidity/codegen/mlir`` has all the mlir lowering code, dialect |
| 134 | +definitions, transformations etc. The code in there is built into the |
| 135 | +``libsolidity`` library by ``libsolidity/CMakeLists.txt``. From now on, all file |
| 136 | +paths are relative to ``libsolidity/codegen/mlir`` (unless stated otherwise). |
| 137 | + |
| 138 | +Dialects |
| 139 | +~~~~~~~~ |
| 140 | +``Sol/`` directory defines the sol dialect, which is a high level dialect to |
| 141 | +represent solidity. Its type-system is defined in ``Sol/SolBase.td`` and its |
| 142 | +operations in ``Sol/SolOps.td``. Similarly ``Yul/`` for the yul dialect, which |
| 143 | +is more or less the yul ir from solc. Both dialects are under the ``mlir`` |
| 144 | +namespaces (``mlir::sol`` and ``mlir::yul``) |
| 145 | + |
| 146 | +``mlir-tblgen`` generates the C++ into the build directory's |
| 147 | +``libsolidity/codegen/mlir/<dialect>/*.inc`` which can be consulted when the |
| 148 | +build errors are harder to follow. |
| 149 | + |
| 150 | +The lowering of high level dialect for evm is under ``Target/EVM``. evm specific |
| 151 | +code and utilities are under the ``evm`` namespace. |
| 152 | + |
| 153 | +Pipeline |
| 154 | +~~~~~~~~ |
| 155 | +``SolidityToMLIR.cpp`` lowers the solidity ast to the sol dialect and |
| 156 | +``YulToMLIR.cpp`` lowers the yul ast to the yul dialect. ``Passes.cpp`` track |
| 157 | +the pass-manager that further lowers the high level dialects. The functions |
| 158 | +under the ``CompilerStack`` are integrated with solc's core pipeline. We try to |
| 159 | +minimize adding functions in ``CompilerStack``, and instead use the |
| 160 | +``solidity::mlirgen`` namespace for things like parsing mlir options, pass |
| 161 | +management etc. This namespace is almost like a dumping ground for everything in |
| 162 | +the mlir codegen that's not in an mlir dialect and neither in the ``evm`` |
| 163 | +namespace. |
| 164 | + |
| 165 | +Builder extensions |
| 166 | +~~~~~~~~~~~~~~~~~~ |
| 167 | +There are generic and target specific utilities. The generic builder extension |
| 168 | +in the ``solidity::mlirgen`` namespace (called ``BuilderExt``) a builder that |
| 169 | +generates frequently used snippets that are not evm specific. While the ``evm`` |
| 170 | +namespace has its own builder for building frequently generated snippets that |
| 171 | +are evm specific. Frequently occurring ir generations should ideally go in one |
| 172 | +of these builder extensions. |
0 commit comments