MLIRについて勉強している。
独自言語を作成し、その中間表現をMLIRを使って表現してみることに挑戦する。
ここで想定する流れは以下の通りだ。
- 独自言語(MYSV : System Verilogオリジナル改造バージョン) を読み込んで、独自形式でASTを作成する
- MYSVのASTをMLIRのツリーに変換する
- MLIRのツリーをダンプする
次はMLIRに変換してダンプできるようになろう。
MLIRの変換およびMLIRのダンプには、MLIRGen.cpp
およびMLIRGen.h
というファイルを作成する。
MLIRGen.hのファイル自体は一番トップレベルのmlirGen(mlir::MLIRContext, ModuleAST)
を宣言する。最もトップレベルでの変換を行うための関数だ。ここから階層的にMLIRに変換する関数を実装していく。
namespace mysv { class ModuleAST; /// Emit IR for the given Mysv moduleAST, returns a newly created MLIR module /// or nullptr on failure. mlir::OwningOpRef<mlir::ModuleOp> mlirGen(mlir::MLIRContext &context, ModuleAST &moduleAST); } // namespace mysv
ModuleAST
の変換から始めていこう。
// The public API for codegen. mlir::OwningOpRef<mlir::ModuleOp> mlirGen(mlir::MLIRContext &context, ModuleAST &moduleAST) { return MLIRGenImpl(context).mlirGen(moduleAST); }
ModuleAST
は、Assign文の集合で構成されるので、内部のAssignExprAST
を繰り返しMLIRに変換する処理で構成されている。
/// Public API: convert the AST for a Mysv module (source file) to an MLIR /// Module operation. mlir::ModuleOp mlirGen(ModuleAST &moduleAST) { // Create a scope in the symbol table to hold variable declarations. ScopedHashTableScope<llvm::StringRef, mlir::Value> varScope(symbolTable); // We create an empty MLIR module and codegen functions one at a time and // add them to the module. theModule = mlir::ModuleOp::create(builder.getUnknownLoc()); for (AssignExprAST &a : moduleAST) mlirGen(a);
このsymbolTable
というのはクラス内で宣言されているメンバ変数で、変数の名前とMLIRのmlir::Value
をマップするためのテーブルらしい。
/// The symbol table maps a variable name to a value in the current scope. /// Entering a function creates a new scope, and the function arguments are /// added to the mapping. When the processing of a function is terminated, the /// scope is destroyed and the mappings created in this scope are dropped. llvm::ScopedHashTable<StringRef, mlir::Value> symbolTable;
AssignExprAST
の変換により、変換用の固定値(数値)のMLIRツリーを作り上げていく。
/// Emit a new function and add it to the MLIR module. mlir::Value mlirGen(AssignExprAST &assignAST) { // Create a scope in the symbol table to hold variable declarations. ScopedHashTableScope<llvm::StringRef, mlir::Value> varScope(symbolTable); // Create an MLIR function for the given prototype. builder.setInsertionPointToEnd(theModule.getBody()); auto *init = assignAST.getInitVal(); if (!init) { emitError(loc(assignAST.loc()), "missing initializer in variable declaration"); return nullptr; } auto assign = mlirGen(*init); if (!assign) return nullptr;
これにより、とりあえずMLIRを生成してダンプすることができるようになった。
$ ./bin/mysv --emit=mlir ../mlir/examples/mysv/test/assign.sv module { %0 = "mysv.constant"() {value = 0 : si64} : () -> i64 %1 = "mysv.constant"() {value = 2 : si64} : () -> i64 }