Skip to content

dialect macro generates builders that don't set the results of operations #719

@V0ldek

Description

@V0ldek

As an example, try this simple single operation from the MLIR Toy Tutorial:

#ifndef TOY_OPS
#define TOY_OPS

include "mlir/IR/OpBase.td"

def Toy_Dialect : Dialect {
  let name = "toy";
  let cppNamespace = "::mlir::toy";
}
class Toy_Op<string mnemonic, list<Trait> traits = []> :
    Op<Toy_Dialect, mnemonic, traits>;

def TransposeOp : Toy_Op<"transpose"> {
  let summary = "transpose operation";

  let arguments = (ins F64Tensor:$input);
  let results = (outs F64Tensor);

  // Allow building a TransposeOp from the input operand.
  let builders = [
    OpBuilder<(ins "Value":$input)>
  ];
}

#endif // TOY_OPS

Use the macro:

mod melior_gen {
    melior::dialect! {
        name: "toy",
        files: ["src/dialect/toy.td"]
    }
}

This results in the following builder (I cleaned up the code a bit to be more readable):

pub(crate) mod mre {
    /// Autogenerated dialect module from a `.td` file.
    mod melior_gen {
        pub mod toy {
            use melior::ir::operation::OperationLike;
            use melior::ir::operation::OperationMutLike;

            pub struct TransposeOperation<'c> {
                operation: ::melior::ir::operation::Operation<'c>,
            }
            impl<'c> TransposeOperation<'c> {
                /// Returns a name.
                pub fn name() -> &'static str {
                    "toy.transpose"
                }
                /// Returns a generic operation.
                pub fn as_operation(&self) -> &::melior::ir::operation::Operation<'c> {
                    &self.operation
                }
                /// Creates a builder.
                pub fn builder(
                    context: &'c ::melior::Context,
                    location: ::melior::ir::Location<'c>,
                ) -> TransposeOperationBuilder<'c, ::melior::dialect::ods::__private::Unset> {
                    TransposeOperationBuilder::new(context, location)
                }
                pub fn input(&self) -> Result<::melior::ir::Value<'c, '_>, ::melior::Error> {
                    self.operation.operand(0)
                }
            }
            ///A builder for a [`transpose`](TransposeOperation) operation.
            pub struct TransposeOperationBuilder<'c, O0> {
                builder: ::melior::ir::operation::OperationBuilder<'c>,
                context: &'c ::melior::Context,
                _state: ::std::marker::PhantomData<(O0)>,
            }
            impl<'c,> TransposeOperationBuilder<'c, ::melior::dialect::ods::__private::Unset> {
                pub fn new(context: &'c ::melior::Context, location: ::melior::ir::Location<'c>) -> Self {
                    Self {
                        context,
                        builder: ::melior::ir::operation::OperationBuilder::new(
                            "toy.transpose",
                            location,
                        ),
                        _state: Default::default(),
                    }
                }
            }
            impl<'c> TransposeOperationBuilder<'c, ::melior::dialect::ods::__private::Unset> {
                pub fn input(self, input: ::melior::ir::Value<'c, '_>) -> TransposeOperationBuilder<
                    'c,
                    ::melior::dialect::ods::__private::Set,
                > {
                    TransposeOperationBuilder {
                        context: self.context,
                        builder: self.builder.add_operands(&[input]),
                        _state: Default::default(),
                    }
                }
            }
            impl<'c> TransposeOperationBuilder<'c, ::melior::dialect::ods::__private::Set> {
                pub fn build(self) -> TransposeOperation<'c> {
                    self.builder
                        .build()
                        .expect("valid operation")
                        .try_into()
                        .expect("should be a valid TransposeOperation")
                }
            }
            #[allow(clippy::too_many_arguments)]
            ///Creates a [`transpose`](TransposeOperation) operation.
            pub fn transpose<'c>(
                context: &'c ::melior::Context,
                input: ::melior::ir::Value<'c, '_>,
                location: ::melior::ir::Location<'c>,
            ) -> TransposeOperation<'c> {
                TransposeOperation::builder(context, location).input(input).build()
            }
        }
    }
}
  1. At no point is the operation configured to have one result of the F64Tensor type. Transpose operations created from this module will always have zero results, which is incorrect. As far as I can see this applies to every operation generated with the macro currently – they're all resultless. The workaround is to write all this code yourself, but that defeats the purpose of the macro.
  2. As a secondary, smaller issue – I'd expect the builder to validate that the input argument provided conforms to the definition in TableGen, i.e. that it is actually of the F64Tensor type.
  3. I also think that currently the builder field in the TableGen definition is completely ignored, I couldn't get any behaviour difference by changing or removing it.
  4. It is really confusing to use this macro, because there is zero documentation on what it does. I would really appreciate at least a shortlist of parts of the MLIR ODS framework that are actually supported. For example, the hasVerifier field has no effect – it would be nice to read this in the doc instead of having to figure it out by experimentation and reading the generated code (no one likes reading generated code, right).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions