Upgrade to Pro — share decks privately, control downloads, hide ads and more …

LLVM IR入門

rchaser53
September 05, 2018

LLVM IR入門

rchaser53

September 05, 2018
Tweet

More Decks by rchaser53

Other Decks in Programming

Transcript

  1. Rust
    でLLVM IR
    入門
    @rchaser53

    View full-size slide


  2. ?

    ?
    職業:
    雑用 web
    エンジニア
    名前:
    吉澤 峻行
    最近はVue
    とかGo
    とか

    View full-size slide

  3. を用いてhello world
    する話
    思いの外hello world
    で苦戦したので書いた
    プリントデバッグに必要な知識だから仕方ないね
    LLVM IR
    をこれから触る方の足しになれば幸いです
    llvm-sys.rs

    View full-size slide

  4. 前座が長いので本題だけ見たい方は
    前座が長いので本題だけ見たい方は
    14
    ページまでジャンプしていただければ…
    サンプルの
    loop, if, struct
    の使用などのサンプルもある(
    暇なら)
    レポジトリ

    View full-size slide

  5. LLVM
    とは
    ?
    LLVM
    とは
    ?
    コンパイラ基盤を作るプロジェクト
    ツールチェーンやコンパイラ、モジュールなどを提供
    Rust
    もLLVM
    を使用している

    View full-size slide

  6. LLVM IR
    とは
    ?
    LLVM IR
    とは
    ?
    LLVM
    はThree-stage compiler structure
    を採用している
    LLVM IR
    は各フェイズ間のデータのやりとりに使う

    View full-size slide

  7. THREE-STAGE COMPILER STRUCTURE
    THREE-STAGE COMPILER STRUCTURE
    複数のフェイズに分けて開発するコンパイラの設計方法
    フロントエンド
    パース,
    エラーチェック、AST
    の生成など
    ミドルエンド(Optimizer)
    最適化、高速化など
    バックエンド
    各プラットフォーム向けの最終産物の生成など
    IR
    を用いて各フェイズでデータのやり取りをする

    View full-size slide

  8. LLVM IR
    とは
    ?
    LLVM IR
    とは
    ?
    こんな感じで各フェイズ間のデータのやりとりに使う
    以下でRust
    でも見れる
    cargo rustc -- --emit=llvm-ir

    View full-size slide

  9. 背景
    背景
    をRust
    で書いてる
    じゃあ改良して任意のLLVM IR
    を出力してみよう
    Go
    言語でつくるインタプリタ
    制作途中のものはこれ
    もうやった人いる

    View full-size slide

  10. 背景
    背景
    hello world
    までの道のりが辛い
    資料らしい資料がない
    では自分で書こう(
    イマココ)

    View full-size slide

  11. 何を使うの
    ?
    何を使うの
    ?
    というLLVM IR
    を出力するモジュールを使う
    LLVM
    はLLVM IR
    を出力するモジュールを提供している
    C
    とC++
    で書かれておりllvm-sys.rs
    はC
    のやつをbinding
    している
    llvm-sys.rs

    View full-size slide

  12. LLVM-SYS.RS
    LLVM-SYS.RS
    非常に薄い。ほとんどC
    のAPI
    と大差ない
    ドキュメントやサンプルはほぼない
    C
    のAPI
    に関しても少ない。C++
    ならいくらか
    困ったら を見に行くのをオススメ
    ponyc

    View full-size slide

  13. 何が難しい
    ?
    何が難しい
    ?
    GetElementPtr(GEP)
    が難しいと思う
    まである
    LLVM IR
    上で直にいじるのにも慣れがいる
    C
    のAPI
    やリファレンスが正直わかりにくいのも原因
    公式の専用の解説ページ

    View full-size slide

  14. GEP(GETELEMENTPTR)
    とは
    GEP(GETELEMENTPTR)
    とは
    Array
    やStruct
    のsubelement
    のアドレスを取得する
    つまりArray
    やStruct
    を操作する際に把握が必須
    文字列はi8
    のArray
    。hello world
    するにはこいつが必要

    View full-size slide

  15. まずは
    LLVM IR
    で出力できるようにする
    まずは
    LLVM IR
    で出力できるようにする
    拡張子はll
    。test.ll
    とか作れば良い
    LLVM
    のツールチェーンであるlli
    を用いて実行すると楽
    $ lli test.ll

    View full-size slide

  16. 多分の最小の構成
    define i32 @main(i32, i8**) {
    entry:
    %local_str = alloca [12 x i8]
    store [12 x i8] c"hello world\00", [12 x i8]* %local_str
    %input_puts = getelementptr [12 x i8], [12 x i8]* %local_str, i32 0
    call i32 @printf(i8* %input_puts)
    ret i32 0
    }
    declare i32 @printf(i8*)

    View full-size slide

  17. 解説1
    ; 頭文字 ; 行
    ; @xxx 変数 %yyy 変数 型
    ; 戻 値 型 関数名(引数 型1, 引数 型2)
    define i32 @main(i32, i8**) {
    ; 必須
    entry:
    %local_str = alloca [12 x i8]
    store [12 x i8] c"hello world\00", [12 x i8]* %local_str
    %input_puts = getelementptr [12 x i8], [12 x i8]* %local_str, i32 0
    call i32 @printf(i8* %input_puts)
    ret i32 0
    }

    View full-size slide

  18. 解説2
    define i32 @main(i32, i8**) {
    entry:
    ; 確保
    ; [12 x i8] 要素 12 Array
    %local_str = alloca [12 x i8]
    ; 確保 値 設定
    ; 基本的 型 値 形 記述
    ; (例) [12 x i8] c"hello world\00"
    store [12 x i8] c"hello world\00", [12 x i8]* %local_str
    ; getelementptr(後述)
    %input_puts = getelementptr [12 x i8], [12 x i8]* %local_str, i32 0
    call i32 @printf(i8* %input_puts)
    i

    View full-size slide

  19. 解説3
    define i32 @main(i32, i8**) {
    entry:
    %local_str = alloca [12 x i8]
    store [12 x i8] c"hello world\00", [12 x i8]* %local_str
    %input_puts = getelementptr [12 x i8], [12 x i8]* %local_str, i32 0
    ; 関数呼 出
    call i32 @printf(i8* %input_puts)
    ; return
    ret i32 0
    }
    ; 標準 呼 出 関数 指定
    declare i32 @printf(i8*)

    View full-size slide

  20. LLVM IR

    GEP
    LLVM IR

    GEP
    Array
    やStruct
    のsubelement
    のアドレスを取得する
    引数のパターンはいくらかある
    llvm-sys.rs
    から出力できないパターンは割愛
    ; 型, 型 変数, index1, index2, ...(以下状況 変更)
    getelementptr %[12 x i8], %[12 x i8]* %local_str, i32 0, i32 0
    型,
    型のポインタはわかるけど、index
    は何?
    => Array
    やStruct
    で考えてみる

    View full-size slide

  21. LLVM IR

    GEP(ARRAY)
    LLVM IR

    GEP(ARRAY)
    // 感 Array 値 取得
    int temp_array[4][4];
    temp_array[1][3];
    ; 上記 型 宣言
    %array_type = type [4 x [4 x i8]]
    define i8* @test_array_gep(%array_type* %a) {
    entry:
    %ret_val = getelementptr %array_type, %array_type* %a, i32 0, i
    ret i8* %ret_val
    }

    View full-size slide

  22. LLVM IR

    GEP(STRUCT)
    LLVM IR

    GEP(STRUCT)
    // 感 Struct 値 取得
    struct temp_struct {
    char a;
    int b
    int c[4];
    };
    temp_struct.b
    ; 上記 型 宣言
    %struct_type = type { i8, i32, [4 x i8] }
    define i32* @test_stuct_gep(%struct_type* %s) {
    entry:
    ; 直接field名 指定 肩 宣言 順番 記述
    ; b 2 目 宣言 1
    %ret_val = getelementptr %struct_type, %struct_type* %s, i32 0,
    ret i32* %ret_val
    }

    View full-size slide

  23. LLVM IR

    GEP
    LLVM IR

    GEP
    ; 型, 型 変数, index1, index2, ...(以下状況 変更)
    getelementptr %[12 x i8], %[12 x i8]* %local_str, i32 0, i32 0
    常にindex1
    が0
    にならない…?

    View full-size slide

  24. LLVM IR

    GEP
    LLVM IR

    GEP
    index1
    が0
    以外のケース。ないことはないらしい…
    // C
    struct munger_struct {
    int f1;
    int f2;
    };
    void munge(struct munger_struct *P) {
    P[0].f1 = P[1].f1 + P[2].f2;
    }
    ; LLVM IR
    void %munge(%struct.munger_struct* %P) {
    entry:
    %tmp = getelementptr %struct.munger_struct, %struct.munger_struct
    %tmp = load i32* %tmp
    %tmp6 = getelementptr %struct.munger_struct, %struct.munger_struc
    %tmp7 = load i32* %tmp6
    %tmp8 = add i32 %tmp7, %tmp
    %tmp9 = getelementptr %struct.munger_struct, %struct.munger_struc
    store i32 %tmp8, i32* %tmp9
    ret void
    }

    View full-size slide

  25. LLVM-SYS.RS
    LLVM-SYS.RS
    基本はllvm-sys.rs
    のexample
    を参考にすれば良い
    unsafe
    とか生ポインタとかの話は割愛
    LLVMBuildGEP
    についての説明をする

    View full-size slide

  26. 作成する
    LLVM IR
    作成する
    LLVM IR
    %local_str = alloca [12 x i8]
    store [12 x i8] c"hello world\00", [12 x i8]* %local_str
    %input_puts = getelementptr [12 x i8], [12 x i8]* %local_str, i32 0,

    View full-size slide

  27. 以下Rust
    のコード
    長いし読みにくいので実際のコードの 貼る
    リンク先のコードの方がいくらかマシだと思う
    次のスライドでgetelementptr
    だけ説明する
    リンク
    pub fn codegen_string(
    builder: *mut LLVMBuilder,
    context: *mut LLVMContext,
    input_str: &str,
    ) -> *mut LLVMValue {
    let length = input_str.len() as u32;
    unsafe {
    // %local_str = alloca [12 x i8]
    let llvm_value = LLVMBuildAlloca(
    builder,
    LLVMArrayType(LLVMInt8Type(), length),
    c_string!("").as_ptr(),
    );
    // i \ i

    View full-size slide

  28. お作法なので知ってしまえば簡単
    お作法なので知ってしまえば簡単
    // getelementptr [12 x i8], [12 x i8]* %local_str, i32 0, i32 0
    // i32 0, i32 0
    let mut args = [
    LLVMConstInt(LLVMInt32Type(), 0, 0),
    LLVMConstInt(LLVMInt32Type(), 0, 0),
    ];
    return LLVMBuildGEP(
    builder,
    llvm_value, // Array Struct
    args.as_mut_ptr(),
    args.len() as u32, // 第3引数 length 引数 指定 意味
    CString::new("").unwrap().as_ptr(), // 空文字 場合 勝手 変数名 生成
    );

    View full-size slide

  29. まとめ
    1
    まとめ
    1
    GETELEMENTPTR
    について
    GETELEMENTPTR
    について
    慣れればそこまで難しいものではないと思う
    使えないとほぼ何もできないので勉強できて良かった
    C
    のAPI
    使われてなさすぎな気がするのだけど何故?

    View full-size slide

  30. まとめ
    2
    まとめ
    2
    LLVM-SYS.RS

    LLVM IR
    を出力する意味はあるのか
    ?
    LLVM-SYS.RS

    LLVM IR
    を出力する意味はあるのか
    ?
    あまりなさそう。Rust
    でLLVM IR
    を出力すれば良さそう
    な気はする
    しかしLLVM IR
    について知れたのは良いことなのでは?
    まぁその時楽しめれば良いよね

    View full-size slide

  31. 参考リンク
    公式reference
    公式のGetElementPtr
    の詳細な解説
    ponyc
    のレポジトリ(
    困ったら読む)
    The Architecture of Open Source Applications
    のLLVM
    Three-stage_compiler_structure
    きつねさんでもわかるLLVM

    View full-size slide

  32. ご静聴ありがとうございました
    !
    ご静聴ありがとうございました
    !

    View full-size slide