TL; DR
- TableGenの自動生成ファイルは2か所でincludeが必要
- マクロ定義によって挿入される内容が切り替わる(クラス定義 or クラス名一覧)ため
はじめに
MLIRで言語処理系を作っていたところ1、TableGenの自動生成ファイルを利用するために同じファイルを2回includeする必要が出てきました。
// 同じファイルを2回インクルードしている!
#define GET_OP_CLASSES
#include "filskalang/CodeGen/Ops.cpp.inc"
void FilskalangDialect::initialize() {
addOperations<
#define GET_OP_LIST
#include "filskalang/CodeGen/Ops.cpp.inc"
>();
}
上記は公式チュートリアルのtoy言語実装を参考にして作成したものです。
はじめはチュートリアルの誤植かと思い片方を消してみたら、コンパイルエラーが発生してしまいました。
そこで本記事では、なぜ2回includeが必要なのか調べてみました。
自動生成ファイルの内容
Ops.cpp.inc
の中身は以下のような形式になっていました。
#ifdef GET_OP_LIST
#undef GET_OP_LIST
mlir::filskalang::HltOp,
mlir::filskalang::PrtOp,
mlir::filskalang::SetOp,
mlir::filskalang::SubprogramOp
#endif // GET_OP_LIST
#ifdef GET_OP_CLASSES
#undef GET_OP_CLASSES
namespace mlir {
namespace filskalang {
static ::mlir::LogicalResult __mlir_ods_local_attr_constraint_Ops0(
::mlir::Attribute attr, ::llvm::StringRef attrName, llvm::function_ref<::mlir::InFlightDiagnostic()> emitError) {
if (attr && !((::llvm::isa<::mlir::StringAttr>(attr))))
return emitError() << "attribute '" << attrName
<< "' failed to satisfy constraint: string attribute";
return ::mlir::success();
}
// ...
} // namespace filskalang
} // namespace mlir
MLIR_DEFINE_EXPLICIT_TYPE_ID(mlir::filskalang::SubprogramOp)
#endif // GET_OP_CLASSES
役割の詳細は本題ではないので割愛しますが、ファイル内はマクロ定義によって大きく2つの部分に分かれています。
GET_OP_CLASSES
GET_OP_CLASSES
が定義されている場合は、クラスや関数の定義のみ挿入されます。include
で想像する一般的な使い方です。
namespace mlir {
namespace filskalang {
static ::mlir::LogicalResult __mlir_ods_local_attr_constraint_Ops0( /*...*/) {
// ...
}
// ...
} // namespace filskalang
} // namespace mlir
GET_OP_CLASSES
一方、GET_OP_CLASSES
が定義されている場合は、クラス一覧のみ挿入されます。
mlir::filskalang::HltOp,
mlir::filskalang::PrtOp,
mlir::filskalang::SetOp,
mlir::filskalang::SubprogramOp
このクラス一覧は addOperations
のテンプレート引数として使用されます。
void FilskalangDialect::initialize() {
addOperations<
#define GET_OP_LIST
#include "filskalang/CodeGen/Ops.cpp.inc"
>();
}
void FilskalangDialect::initialize() {
addOperations<
mlir::filskalang::HltOp,
mlir::filskalang::PrtOp,
mlir::filskalang::SetOp,
mlir::filskalang::SubprogramOp
>();
}
1つのファイルに異なる2通りの役割を持たせて、マクロによって用途を切り替えていたというわけです。
addOperations
のテンプレート引数はDialectにクラスを登録するために使用されています。
想像ですが、この登録を手軽に行えるようにするため上記のような2回includeする設計を取っていると思われます。
https://mlir.llvm.org/doxygen/classmlir_1_1Dialect.html#a60d2c0fbecac1d2f2714b8387466cfaa
-
「ストレンジコード」のFilska言語をMLIRへ移植しています。https://qiita.com/Syuparn/items/e8f4046c4a5b551db310 ↩