[PSA] (Deprecation warning) Per-pass autogenerated macros and pass options

This is to inform that the code generation for tablegen passes has been recently improved. The docs have already been updated (again, feel free to improve them), but here I provide a short summary of the changes for better transitioning.

  • Individual guards are now being emitted for the passes, and are furthermore differentiated between declarations and definitions (which are respectively guarded by the GEN_PASS_DECL_PASSNAME and GEN_PASS_DEF_PASSNAME macros).
  • All of the code is still generated inside the .h.inc file, but the pass base classes now live inside the impl namespace.
  • If the pass has some options, an options struct is also declared and can be passed to the pass base class constructor to set the options of the pass itself.
  • The constructor field has also become optional within the tablegen declaration and, if not provided, the infrastructure will generate both the C++ declarations and definitions, using a function name that is derived from the pass name.
    Notice that the constructor would still need to be explicitely declared in these cases, even if the name of the function would match the autogenerated one:
    • if living in a namespace that is different from the registration code.
    • if having a return type different from std::unique_ptr<mlir::Pass>

This is an example of how the code should look like when migrating to the new infrastructure:

/** PassName.h */
namespace mlir {
#define GEN_PASS_DECL_PASSNAME
#include "Passes.h.inc"

// If constructor is explicit
std::unique_ptr<mlir::Pass> createPassName(); // Explicit constructor is needed if mlir::Pass has to be replaced with, for example, mlir::OperationPass<>

// If constructor is explicit and pass has options
std::unique_ptr<mlir::Pass> createPassName(const PassNameOptions &options); // Explicit constructor is needed if mlir::Pass has to be replaced with, for example, mlir::OperationPass<>
}


/** Passes.h */
#include "PassName.h"

namespace mlir {
#define GEN_PASS_REGISTRATION
#include "Passes.h.inc"
}


/** PassName.cpp */
namespace mlir {
#define GEN_PASS_DEF_PASSNAME
#include "Passes.h.inc"
}

namespace {
// Name of the class must match the tablegen name if the constructor is autogenerated
struct PassName : public mlir::impl::PassNameBase {
  using PassNameBase::PassNameBase;
  ...
}
}

// If the constructor is explicit
std::unique_ptr<mlir::Pass> mlir::createPassName() {
  return std::make_unique<PassName>();
}

// If constructor is explicit and pass has options
std::unique_ptr<mlir::Pass> mlir::createPassName(const mlir::PassNameOptions& options) {
  return std::make_unique<PassName>(options);
}

For what regards the MLIR core, a GitHub issue has been opened to improve the passes to the new best practices. Any help is welcome, there are also some “design” topics to be discussed among the lines.

The generation of the old pass base classes (guarded by the GEN_PASS_CLASSES macro) has been kept in order to ease the migration of downstream code, but we plan to drop it in something like 6 weeks from now. That should be a sufficient time window to perform the required changes.

2 Likes

Hey, thanks for this PSA. I’m just now seeing this thanks to @burmako pointing me at it. One piece of feedback for the future: it would be good if there was some more automated way to annouce the deprecation. Maybe under GEN_PASS_CLASSES have #warning "See https://discourse.llvm.org/t/psa-deprecation-warning-per-pass-autogenerated-macros-and-pass-options/64998 for upcoming TableGen changes" there or something.

Sorry for the delayed answer, I’ve been quite busy.
Wouldn’t the #warning directive cause issues in builds in -Werror, thus forcing some users to migrate to the new infrastructure?

That seems like it would be an issue for the regular deprecation attributes we put on methods (e.g. has_value() for Optional recently). I guess there is a -Wno-something flag which users with such configurations can use.

They can ignore the warning at their own peril :slight_smile:

Has everything been switched over in-tree yet? I don’t think we should add warnings until the upstream build is clean, and even then the warnings should be when things are imminently changing (build spam is painful).

– River

For what regards the includes and macro definitions, yes. The old infrastructure can potentially be dropped and everything in-tree would countinue working.

The code however is not complete for what regards the “best practices” (basically, naming and usage of autogenerated constructors). I’m trying to update the passes I’m most interested on, but changing all the existing ones is too much for a single person and may require consensus about some things (e.g. namespaces) (and thus the existence of the github issue).

I think that let constructor hasn’t been migrated. I still saw that a lot in core last I checked.

Having Core be a “model” that folks can copy for best practices is one of the most important ways to ensure that the ecosystem follows best practices.

1 Like

I think that let constructor hasn’t been migrated. I still saw that a lot in core last I checked.

Indeed, this is what I’m talking about. The code however would still continue working if the old autogenerated code would be dropped.

Having Core be a “model” that folks can copy for best practices is one of the most important ways to ensure that the ecosystem follows best practices.

I absolutely agree on this, that was the case also for me when I started working with MLIR. I need some help though to cover everything :sweat_smile: