👋

MLIRでHello, World!

2022/12/26に公開

音に聞くMLIRを使ってみようと思ったんですが、公式のチュートリアルとか非公式のブログ記事とか見てもなんか最初からダイアレクトを作成していて、それより手前のとりあえずMLIRで書かれたサンプルコードを動かすというところだけをやってくれている記事が見当たりませんでした。それでもなんとか自力で動かすことができたので、ここではダイアレクトの作成とかは傍に置いておき、簡単にHello, World!するところまでやってみます。ZennにMLIRに関する記事ってまだ一つもないようですし、最初にふさわしいネタですよね。

hello.mlir
module {
	memref.global "private" constant @string : memref<14xi8> = dense<[0x48,0x65,0x6c,0x6c,0x6f,0x2c,0x20,0x57,0x6f,0x72,0x6c,0x64,0x21,0]>
	llvm.func external @puts(!llvm.ptr<i8>) -> ()
	func.func @main() -> i64 {
		%c0_i64 = arith.constant 0 : i64
		%0 = memref.get_global @string : memref<14xi8>
		%1 = memref.extract_aligned_pointer_as_index %0 : memref<14xi8> -> index
		%2 = arith.index_cast %1 : index to i64
		%3 = llvm.inttoptr %2 : i64 to !llvm.ptr<i8>
		llvm.call @puts(%3) : (!llvm.ptr<i8>) -> ()
		return %c0_i64 : i64
	}
}

MLIRはまだまだ発展途上で、今回もmemref.extract_aligned_pointer_as_indexというかなり新しめのオペレーションを利用しており、LLVMのmainブランチをクローンしてきて自前ビルドする必要があります(筆者が使ったのは52bff450dd)。ビルドコマンドは以下の通り。

cmake -S llvm -B build -G "Unix Makefiles" \
	-DCMAKE_BUILD_TYPE=Release \
	-DCMAKE_INSTALL_PREFIX="$PWD" \
	-DLLVM_ENABLE_ZLIB=OFF \
	-DLLVM_ENABLE_ZSTD=OFF \
	-DLLVM_ENABLE_BINDINGS=OFF \
	-DLLVM_ENABLE_PROJECTS=mlir \
	-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
	-DLLVM_CCACHE_BUILD=OFF
make -C build -j`nproc` install

ずらずらと並んでいるコマンドラインオプションは出てきたエラーを見ながらググったりしてちまちま設定したものなので、環境によっては少し変えないとうまくいかないかもしれません(ちなみに筆者の環境はM1 MacBook Air、macOS 12.5.1です)。ビルドが済んだらカレントディレクトリにインストールされるので、./bin$PATHを通して各種コマンドラインツールを使えるようにしてください。

冒頭のテキストをhello.mlirなどに保存したら、それを以下のコマンドでLLVM IRに変換します。

mlir-opt \
	--convert-arith-to-llvm \
	--convert-func-to-llvm \
	--convert-memref-to-llvm \
	--reconcile-unrealized-casts \
	hello.mlir | mlir-translate --mlir-to-llvmir > hello.ll

以下のようなLLVM IRコードが出来上がります。

hello.ll
; ModuleID = 'LLVMDialectModule'
source_filename = "LLVMDialectModule"

@string = private constant [14 x i8] c"Hello, World!\00"

declare ptr @malloc(i64)

declare void @free(ptr)

declare void @puts(ptr)

define i64 @main() {
  call void @puts(ptr @string)
  ret i64 0
}

!llvm.module.flags = !{!0}

!0 = !{i32 2, !"Debug Info Version", i32 3}

lliで実行してハロワ完了。

> lli hello.ll
Hello, World!

もちろんclangで実行可能形式にすることもできます。

> llc -filetype=obj hello.ll -o hello.o
> clang hello.o -o hello
> ./hello
Hello, World!

草草

Discussion