Macro for OpBuilder::create autocompletion

This is a macro I wrote to replace OpBuilder::create<>(), since Clangd can’t autocomplete parameter packs. It works by generating and immediately calling a lambda with a YourOp::build() call, filling in the varargs. It also optionally adds an attribute encoding the compiler source location where the op was created, which helps a lot with debugging (here implemented with c++20 std::source_location, but could conceivably be done with builtin macros too). It works with parameter autocompletion and with inlays.

It’s not something that should end up in production code (macros are scary), but it certainly makes writing and debugging much more pleasant.

inline mlir::Attribute getDebugLoc(mlir::OpBuilder builder,
                                   std::source_location debug_loc) {
  auto str = std::string();
  str += debug_loc.file_name();
  str += ":";
  str += std::to_string(debug_loc.line());
  str += ":";
  str += std::to_string(debug_loc.column());
  auto loc = builder.getStringAttr(str);
  return loc;
}

#ifdef YOURPROJECT_DEBUG
#define YOURPROJECT_SET_DEBUG_LOC_ATTR(___debug_loc)                           \
  ___OP->setAttr("debug_loc", getDebugLoc(___BUILDER, ___debug_loc));
#else
#define YOURPROJECT_SET_DEBUG_LOC_ATTR
#endif

#ifdef YOURPROJECT_DEBUG
#define YOURPROJECT_DEBUG_LOC_PARAM                                            \
  std::source_location debug_loc = std::source_location::current()
#else
#define YOURPROJECT_DEBUG_LOC_PARAM
#endif

// Help with op autocompletion and debugging. Arguments:
// - op type
// - builder
// - op location
// - YourOp::build() arguments
#define CREATE(___type, ___builder, ___loc, ...)                               \
  [&](YOURPROJECT_DEBUG_LOC_PARAM) {                                           \
    using ___TYPE = ___type;                                                   \
    OperationState ___STATE{___loc, ___TYPE::getOperationName()};              \
    OpBuilder ___BUILDER = ___builder;                                         \
    ___TYPE::build(___BUILDER, ___STATE, __VA_ARGS__);                         \
    ___TYPE ___OP = dyn_cast<___TYPE>(___BUILDER.create(___STATE));            \
    YOURPROJECT_SET_DEBUG_LOC_ATTR(debug_loc)                                  \
    return ___OP;                                                              \
  }()

While I don’t expect anyone to use this, I’d be interested in opinions, alternatives, and just as a primer for discussing different workflows.

2 Likes