Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Draft: Dialect generation from ODS (#274)
I've created an early draft of dialect generation based on the [MLIR Python Bindings](https://mlir.llvm.org/docs/Bindings/Python/#integration-with-ods). It's okay if you don't have the time to review this. I admit that there's quite a lot of ugly and hard to read code (especially the code dealing with variadic arguments), and it might not be in a state currently where you would want to maintain it within `melior`, hence I'm marking it as a draft. Not much changed since my original implementation mentioned in #262, but I got a bit stuck on error handling in my TableGen wrapper library ([tblgen-rs](https://gitlab.com/Danacus/tblgen-rs)) and lost motivation for a while after that. Anyway, I decided to finish what I started, hence I am making this draft. To build this branch, you might need to set `TABLEGEN_160_PREFIX` to match `MLIR_SYS_160_PREFIX`. I've added the generated dialects in a new `dialect_gen` module for now, such that they can be compared with the original hand-written bindings in the `dialect` module. There are still a few issues: - [ ] Some parts of the code are hacky and ugly, and may be hard to read. - [ ] Type inference is not always detected (but it should be as good as the Python bindings at least) - [ ] Need to add tests (already have them in a separate repository) - [ ] Need to fix some issues with the CI I wanted complete parity with the existing hand-written dialect bindings, but there are some things that aren't generated as nicely. For example, `arith::CmpiPredicate` is not generated and plain `Attribute` is used instead for `arith::cmpi`. It might be feasible to generate dialect specific attributes from ODS instead. Or perhaps being able to write some function manually would be useful. Currently I generate wrapper types around `Operation` that provide additional methods, for example: ```rust pub struct AddIOp<'c> { operation: ::melior::ir::operation::Operation<'c>, } impl<'c> AddIOp<'c> { pub fn name() -> &'static str { "arith.addi" } pub fn operation(&self) -> &::melior::ir::operation::Operation<'c> { &self.operation } pub fn builder( location: ::melior::ir::Location<'c>, ) -> AddIOpBuilder<'c, AddIOp__No__Lhs, AddIOp__No__Rhs> { AddIOpBuilder::new(location) } pub fn result(&self) -> ::melior::ir::operation::OperationResult<'c, '_> { self.operation.result(0usize).expect("operation should have this result") } pub fn lhs(&self) -> ::melior::ir::Value<'c, '_> { self.operation .operand(0usize) .expect("operation should have this operand") } pub fn rhs(&self) -> ::melior::ir::Value<'c, '_> { self.operation .operand(1usize) .expect("operation should have this operand") } } ``` I then provide implementations of `Into<Operation>` and `TryFrom<Operation>` to "cast" to and from an `Operation`. ```rust impl<'c> TryFrom<::melior::ir::operation::Operation<'c>> for AddIOp<'c> { type Error = ::melior::Error; fn try_from( operation: ::melior::ir::operation::Operation<'c>, ) -> Result<Self, Self::Error> { Ok(Self { operation }) } } impl<'c> Into<::melior::ir::operation::Operation<'c>> for AddIOp<'c> { fn into(self) -> ::melior::ir::operation::Operation<'c> { self.operation } } ``` I wonder if it would be better to use an `OperationLike` trait, similar to `AttributeLike`? That way we wouldn't have to call `operation` or `into` to use the methods on `Operation`. On a related note: should we also generate `Ref` (and `RefMut`?) types for these operation wrappers? It might be useful to be able to cast a `OperationRef` into a `AddIOpRef`, for example, to more easily analyze operations in external passes (or even external analyses, which is something else I'm working on as well: [mlir-rust-tools](https://gitlab.com/Danacus/mlir-rust-tools)).
- Loading branch information