Inherit from MLIR class fails because of type id resolver

For a prototype, I would like to reuse some operations of some in-tree dialects with only some slight modifications (e.g., a changed operation name). For example, I would like to create a mir.switch operation that for now is equivalent to the cf.switch operation, but might deviate in the future.

I would like to avoid copying the tablegen definition from ControlFlowOps.td along other stuff like the definitions for parsing the custom assembly format from ControlFlowOps.cpp. Hence, I tried to extend the mlir::cf::SwitchOp class and only override the getOperationName() method like so in my Mir.h:

#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/OpDefinition.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/Interfaces/CastInterfaces.h"
#include "mlir/Interfaces/ControlFlowInterfaces.h"
#include "mlir/Interfaces/InferTypeOpInterface.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"
#include "mlir/Interfaces/VectorInterfaces.h"

#define GET_OP_CLASSES

namespace mlir {
namespace mir {
// "Copy" the switch op from the `cf` dialect.
class SwitchOp : public mlir::cf::SwitchOp {
public:
  static constexpr ::llvm::StringLiteral getOperationName() {
    return ::llvm::StringLiteral("mir.switch");
  }
};
} // namespace mir
} // namespace mlir
MLIR_DECLARE_EXPLICIT_TYPE_ID(::mlir::mir::SwitchOp)

// clang-format off
#include "mir/MirEnums.h.inc"
#include "mir/Mir.h.inc"

After that, I register the operation in MirDialect.cpp:

// Mir Dialect Implementation.
void MirDialect::initialize() {
  // [...]
  addOperations<::mlir::mir::SwitchOp>();
}

However, the build fails with

Undefined symbols for architecture x86_64:
  "mlir::detail::TypeIDResolver<mlir::mir::Mir_SwitchOp, void>::id", referenced from:
      mlir::detail::TypeIDResolver<mlir::mir::Mir_SwitchOp, void>::resolveTypeID() in libMLIRmir.a(MirDialect.cpp.o)
ld: symbol(s) not found for architecture x86_64

May anyone give me a hint what the problem here is? The problem only happens for this operation where I inherited from another operation, not for those that were generated by TableGen. I realized that in the error message, there is a second template parameter next to the operation, which is void. Unfortunately, I was not able to trace back where this might come from.

P.S. I hope this is the right forum for these kinds of topics. If not, I will ask on StackOverflow…

Disclaimer to begin with: these classes are not designed for inheritance and I don’t know what kind of issue may occurs down the line.

Now for the immediate issue, there is some doc in llvm-project/TypeID.h at main · llvm/llvm-project · GitHub

And if you look in the code generated by TableGen you will see:

$ grep TYPE_ID.*SwitchOp tools/mlir/include/mlir/Dialect/SCF/IR/SCFOps.h.inc
MLIR_DECLARE_EXPLICIT_TYPE_ID(::mlir::scf::IndexSwitchOp)
$ grep TYPE_ID.*SwitchOp tools/mlir/include/mlir/Dialect/SCF/IR/SCFOps.cpp.inc
MLIR_DEFINE_EXPLICIT_TYPE_ID(::mlir::scf::IndexSwitchOp)

These are both at the top-level, not in a namespace.

1 Like

Thank you @mehdi_amini for you very fast reply :+1:t2: My macros for the TYPE_ID are already at the top level of my files (meaning not in any namespace). However, your reply still solved the issue for me, as I only used the MLIR_DECLARE_EXPLICIT_TYPE_ID but not the MLIR_DEFINE_EXPLICIT_TYPE_ID. Hence, my problem is solved, so thank you again :raised_hands:t2:

Regarding your disclaimer, you’re absolutely right. I didn’t have any expectations that this will work, and in fact I am prompted with errors that seem to originate from failed casts. Nevertheless, it was worth a try…

1 Like