[MLIR] Convert DialectReductionPatternInterface using ODS (#180640)

This PR converts `DialectReductionPatternInterface` using ODS.

It also introduces a new Interface Method class:

`PureVirtualInterfaceMethod` which creates the method as pure virtual.
This commit is contained in:
AidinT 2026-02-16 19:04:38 +01:00 committed by GitHub
parent f530c161a7
commit f46c2c46d1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 133 additions and 49 deletions

View file

@ -85,6 +85,11 @@ class StaticInterfaceMethod<string desc, string retTy, string methodName,
: InterfaceMethod<desc, retTy, methodName, args, methodBody,
defaultImplementation>;
// This class represents a pure virtual interface method.
class PureVirtualInterfaceMethod<string desc, string retTy, string methodName,
dag args = (ins)>
: InterfaceMethod<desc, retTy, methodName, args>;
// This class represents a interface method declaration.
class InterfaceMethodDeclaration<string desc, string retTy, string methodName,
dag args = (ins)>

View file

@ -2,4 +2,8 @@ set(LLVM_TARGET_DEFINITIONS Passes.td)
mlir_tablegen(Passes.h.inc -gen-pass-decls -name Reducer)
add_mlir_generic_tablegen_target(MLIRReducerIncGen)
set(LLVM_TARGET_DEFINITIONS DialectReductionPatternInterface.td)
mlir_tablegen(DialectReductionPatternInterface.h.inc -gen-dialect-interface-decls)
add_mlir_generic_tablegen_target(MLIRDialectReductionPatternInterfaceIncGen)
add_mlir_doc(Passes ReducerPasses ./ -gen-pass-doc)

View file

@ -0,0 +1,59 @@
#ifndef MLIR_INTERFACES_DIALECTREDUCTIONPATTERNINTERFACE
#define MLIR_INTERFACES_DIALECTREDUCTIONPATTERNINTERFACE
include "mlir/IR/Interfaces.td"
def DialectReductionPatternInterface : DialectInterface<"DialectReductionPatternInterface"> {
let description = [{
This is used to report the reduction patterns for a Dialect. While using
mlir-reduce to reduce a module, we may want to transform certain cases into
simpler forms by applying certain rewrite patterns. Implement the
`populateReductionPatterns` to report those patterns by adding them to the
RewritePatternSet.
Example:
MyDialectReductionPattern::populateReductionPatterns(
RewritePatternSet &patterns) {
patterns.add<TensorOpReduction>(patterns.getContext());
}
For DRR, mlir-tblgen will generate a helper function
`populateWithGenerated` which has the same signature therefore you can
delegate to the helper function as well.
Example:
MyDialectReductionPattern::populateReductionPatterns(
RewritePatternSet &patterns) {
// Include the autogen file somewhere above.
populateWithGenerated(patterns);
}
}];
let cppNamespace = "::mlir";
let methods = [
PureVirtualInterfaceMethod<[{
Patterns provided here are intended to transform operations from a complex
form to a simpler form, without breaking the semantics of the program
being reduced. For example, you may want to replace the
tensor<?xindex> with a known rank and type, e.g. tensor<1xi32>, or
replacing an operation with a constant.
}],
"void", "populateReductionPatterns",
(ins "::mlir::RewritePatternSet &":$patterns)
>,
InterfaceMethod<[{
This method extends `populateReductionPatterns` by allowing reduction
patterns to use a `Tester` instance. Some reduction patterns may need to
run tester to determine whether certain transformations preserve the
"interesting" behavior of the program. This is mostly useful when pattern
should choose between multiple modifications.
}],
"void", "populateReductionPatternsWithTester",
(ins "::mlir::RewritePatternSet &":$patterns, "::mlir::Tester &":$tester),
[{}]
>
];
}
#endif

View file

@ -13,52 +13,9 @@
#include "mlir/Reducer/Tester.h"
namespace mlir {
class RewritePatternSet;
/// This is used to report the reduction patterns for a Dialect. While using
/// mlir-reduce to reduce a module, we may want to transform certain cases into
/// simpler forms by applying certain rewrite patterns. Implement the
/// `populateReductionPatterns` to report those patterns by adding them to the
/// RewritePatternSet.
///
/// Example:
/// MyDialectReductionPattern::populateReductionPatterns(
/// RewritePatternSet &patterns) {
/// patterns.add<TensorOpReduction>(patterns.getContext());
/// }
///
/// For DRR, mlir-tblgen will generate a helper function
/// `populateWithGenerated` which has the same signature therefore you can
/// delegate to the helper function as well.
///
/// Example:
/// MyDialectReductionPattern::populateReductionPatterns(
/// RewritePatternSet &patterns) {
/// // Include the autogen file somewhere above.
/// populateWithGenerated(patterns);
/// }
class DialectReductionPatternInterface
: public DialectInterface::Base<DialectReductionPatternInterface> {
public:
/// Patterns provided here are intended to transform operations from a complex
/// form to a simpler form, without breaking the semantics of the program
/// being reduced. For example, you may want to replace the
/// tensor<?xindex> with a known rank and type, e.g. tensor<1xi32>, or
/// replacing an operation with a constant.
virtual void populateReductionPatterns(RewritePatternSet &patterns) const = 0;
/// This method extends `populateReductionPatterns` by allowing reduction
/// patterns to use a `Tester` instance. Some reduction patterns may need to
/// run tester to determine whether certain transformations preserve the
/// "interesting" behavior of the program. This is mostly useful when pattern
/// should choose between multiple modifications.
virtual void populateReductionPatternsWithTester(RewritePatternSet &patterns,
Tester &tester) const {}
protected:
DialectReductionPatternInterface(Dialect *dialect) : Base(dialect) {}
};
} // namespace mlir
#include "mlir/Reducer/DialectReductionPatternInterface.h.inc"
#endif // MLIR_REDUCER_REDUCTIONPATTERNINTERFACE_H

View file

@ -47,6 +47,9 @@ public:
// Return if this method is static.
bool isStatic() const;
// Return if the method is a pure virtual one.
bool isPureVirtual() const;
// Return if the method is only a declaration.
bool isDeclaration() const;

View file

@ -12,6 +12,7 @@ add_mlir_library(MLIRReduce
DEPENDS
MLIRReducerIncGen
MLIRDialectReductionPatternInterfaceIncGen
)
mlir_check_all_link_libraries(MLIRReduce)

View file

@ -52,6 +52,11 @@ bool InterfaceMethod::isStatic() const {
return def->isSubClassOf("StaticInterfaceMethod");
}
// Return if the method is a pure virtual one.
bool InterfaceMethod::isPureVirtual() const {
return def->isSubClassOf("PureVirtualInterfaceMethod");
}
// Return if the method is only a declaration.
bool InterfaceMethod::isDeclaration() const {
return def->isSubClassOf("InterfaceMethodDeclaration");

View file

@ -22,9 +22,9 @@ def NoDefaultMethod : DialectInterface<"NoDefaultMethod"> {
// DECL: class NoDefaultMethod : public {{.*}}DialectInterface::Base<NoDefaultMethod>
// DECL: public:
// DECL: NoDefaultMethod(::mlir::Dialect *dialect) : Base(dialect) {}
// DECL: virtual bool isExampleDialect() const {}
// DECL: virtual unsigned supportSecondMethod(::mlir::Type type) const {}
// DECL: NoDefaultMethod(::mlir::Dialect *dialect) : Base(dialect) {}
def WithDefaultMethodInterface : DialectInterface<"WithDefaultMethodInterface"> {
let description = [{
@ -73,3 +73,24 @@ def OnlyDeclarationInterfaceWithExtraDecls : DialectInterface<"OnlyDeclarationIn
// DECL: class OnlyDeclarationInterfaceWithExtraDecls : public {{.*}}DialectInterface::Base<OnlyDeclarationInterfaceWithExtraDecls>
// DECL: virtual void exampleMethodDeclaration(::mlir::Type type) const;
// DECL: using DeclType = int;
def PureVirtualInterface : DialectInterface<"PureVirtualInterface"> {
let description = [{
This is an example dialect interface with pure virtual methods.
}];
let cppNamespace = "::mlir::example";
let methods = [
PureVirtualInterfaceMethod<
"Check if it's an example dialect", "bool", "isExampleDialect",
(ins)
>
];
}
// DECL: class PureVirtualInterface : public {{.*}}DialectInterface::Base<PureVirtualInterface>
// DECL: public:
// DECL: virtual bool isExampleDialect() const = 0;
// DECL: protected:
// DECL-NEXT: PureVirtualInterface(::mlir::Dialect *dialect) : Base(dialect) {}

View file

@ -113,6 +113,11 @@ static void emitInterfaceMethodsDef(const DialectInterface &interface,
continue;
}
if (method.isPureVirtual()) {
ios << " = 0;\n";
continue;
}
// if it is not a method declaration, then it's a normal interface method.
ios << " {";
@ -126,6 +131,27 @@ static void emitInterfaceMethodsDef(const DialectInterface &interface,
}
}
static void emitConstructor(const DialectInterface &interface,
raw_ostream &os) {
raw_indented_ostream ios(os);
// We consider a constructor protected if interface has at least one pure
// virtual method
auto hasProtectedConstructor =
llvm::any_of(interface.getMethods(), [](const InterfaceMethod &method) {
return method.isPureVirtual();
});
ios.indent(0);
if (hasProtectedConstructor)
ios << "protected:\n";
ios.indent(2);
ios << llvm::formatv("{0}(::mlir::Dialect *dialect) : Base(dialect) {{}\n",
interface.getName());
}
void DialectInterfaceGenerator::emitInterfaceDecl(
const DialectInterface &interface) {
llvm::NamespaceEmitter ns(os, interface.getCppNamespace());
@ -135,9 +161,8 @@ void DialectInterfaceGenerator::emitInterfaceDecl(
// Emit the main interface class declaration.
os << llvm::formatv(
"class {0} : public ::mlir::DialectInterface::Base<{0}> {\n"
"public:\n"
" {0}(::mlir::Dialect *dialect) : Base(dialect) {{}\n",
"class {0} : public ::mlir::DialectInterface::Base<{0}> {{\n"
"public:\n",
interface.getName());
emitInterfaceMethodsDef(interface, os);
@ -151,6 +176,10 @@ void DialectInterfaceGenerator::emitInterfaceDecl(
ios << "\n";
}
os << "\n";
emitConstructor(interface, os);
os << "};\n";
}