RustのフロントエンドはLLVMで実装されているらしい。
Rustの文法自体は最近触っていないせいですっかり忘れてしまったが、自作LLVMバックエンドがRustの生成したLLVMを処理することができるようになれば格好いいかもしれない。 とりあえず、RustからLLVMのIRを生成してLLVMバックエンドに渡してみる方法について調査した。
RustのコードからLLVM IRを生成するためには以下のようにすればよいらしい。(Rustでmain無しのライブラリのみ作るためにはどうしたらよいのだ...)
main.rs
fn main() { let _a:u32 = 1 + 2; }
なんか最適化で全部消えてしまいそうな気がするのだが、仕方がない。私のRustの知識は現在は退化しており、これが限界だ。
さて、これからLLVM IRおよびLLVM Bitcodeを生成するためには以下のように処理すればよいらしい。
rustc main.rs --emit=llvm-ir # main.llを生成する rustc main.rs --emit=llvm-bc # main.bcを生成する
これを実行してみると、確かにLLVM IRが生成されている。しかし猛烈に長いな...
main.ll
; ModuleID = 'main.7rcbfp3g-cgu.0' source_filename = "main.7rcbfp3g-cgu.0" target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" ... ; main::main ; Function Attrs: nonlazybind uwtable define internal void @_ZN4main4main17hfe98083a4c87500fE() unnamed_addr #0 { start: ret void }
とりあえず、本家のRISC-V LLVMバックエンドに渡してみる。
./bin/llc -debug -march=riscv32 /home/msyksphinz/work/llvm/myriscvx-tests/rust/rust_simple/src/main.bc -o main.s
を、生成できた。中身を見てみると、RISC-Vのアセンブリが生成されている。良かった。
main.s
.size _ZN4main4main17hfe98083a4c87500fE, .Lfunc_end9-_ZN4main4main17hfe98083a4c87500fE # -- End function .globl main # -- Begin function main .p2align 2 .type main,@function main: # @main # %bb.0: # %top addi sp, sp, -16 sw ra, 12(sp) mv a3, a1 mv a1, a0 lui a0, %hi(_ZN4main4main17hfe98083a4c87500fE) addi a0, a0, %lo(_ZN4main4main17hfe98083a4c87500fE) srai a2, a1, 31 call _ZN3std2rt10lang_start17hd1a40614a9e43128E lw ra, 12(sp) addi sp, sp, 16 ret .Lfunc_end10:
一方で、オリジナルのRISC-VバックエンドMYRISCVXで実行してみた。
./bin/llc -debug -march=myriscvx32 -mcpu=simple32 /home/msyksphinz/work/llvm/myriscvx-tests/rust/rust_simple/src/main.bc -o main.s
スタックフレームの処理でAssertionが落ちてしまった。。。何か機能実装が足りないみたいだ。。。原因を調査する。
Function : _ZN4core3fmt9Arguments6new_v117h9482ffdd5f1340abE <---------> $a1 = LW %stack.0._4, killed $a1 :: (dereferenceable load 4 from %ir.8, align 8) FrameIndex : 0 spOffset : -16 stackSize : 16 llc: /home/msyksphinz/work/llvm/llvm-myriscvx/include/llvm/CodeGen/MachineOperand.h:527: int64_t llvm::MachineOperand::getImm() const: Assertion `isImm() && "Wrong MachineOperand accessor"' failed. Stack dump: