MLIRはMulti Level Intermediate Representationの略で、LLVM IRよりも更にメタ化したような中間言語だ。LLVM IRでは吸収しきれないような各言語で定義される中間表現を、許容するために開発された。
これを使ってみたいので、まずはToyに似たような言語を使って自分でMLIRを生成できるようになりたい。いくつか試行をしている。
MYSVというVerilogに等価な言語を作って、まずはそれをParseしてDumpできるようにする。これまMLIRを生成する前段階だ。
assign A = 0; assign Hoge = 2;
前回まででとりあえず簡単なVerilogをParseできるようになったので、今度はこれをMLIRにビルドしていく、というわけだ。
まずはMLIRを出力できるモードを作る。
switch (emitAction) { case Action::DumpAST: dumpAST(); return 0; case Action::DumpMLIR: dumpMLIR(*moduleAST); return 0; default: llvm::errs() << "No action specified (parsing only?), use -emit=<action>\n"; }
基本的な考え方としては、前回作った自作のASTツリーをMLIRにコンバートしていく。MLIRGen.cpp
を実装していく。
moduleAST
の中に入っているAssignExprAST
に分解していく。mlirGen(AssignExprAST)
に分解していく。
/// Public API: convert the AST for a Mysv module (source file) to an MLIR /// Module operation. mlir::ModuleOp mlirGen(ModuleAST &moduleAST) { // 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); // ... return theModule; }
AssignExprAST
に対するMLIRの構築がこのようになる。引き続きMLIRブロックを作っていく。
/// Emit a new function and add it to the MLIR module. mlir::Value mlirGen(AssignExprAST &assignAST) { auto *init = vardecl.getInitVal(); if (!init) { emitError(loc(vardecl.loc()), "missing initializer in variable declaration"); return nullptr; } mlir::Value value = mlirGen(*init); if (!value) return nullptr; // Register the value in the symbol table. if (failed(declare(vardecl.getName(), value))) return nullptr; return value; }