FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

RustのコードをLLVM IRに変換してRISC-V LLVMバックエンドに渡してみる

f:id:msyksphinz:20190224185310p:plain

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: