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. LLVM IR とは ? LLVM IR とは ? LLVM はThree-stage

    compiler structure を採用している LLVM IR は各フェイズ間のデータのやりとりに使う
  2. THREE-STAGE COMPILER STRUCTURE THREE-STAGE COMPILER STRUCTURE 複数のフェイズに分けて開発するコンパイラの設計方法 フロントエンド パース, エラーチェック、AST

    の生成など ミドルエンド(Optimizer) 最適化、高速化など バックエンド 各プラットフォーム向けの最終産物の生成など IR を用いて各フェイズでデータのやり取りをする
  3. 何を使うの ? 何を使うの ? というLLVM IR を出力するモジュールを使う LLVM はLLVM IR

    を出力するモジュールを提供している C とC++ で書かれておりllvm-sys.rs はC のやつをbinding している llvm-sys.rs
  4. 何が難しい ? 何が難しい ? GetElementPtr(GEP) が難しいと思う まである LLVM IR 上で直にいじるのにも慣れがいる

    C のAPI やリファレンスが正直わかりにくいのも原因 公式の専用の解説ページ
  5. GEP(GETELEMENTPTR) とは GEP(GETELEMENTPTR) とは Array やStruct のsubelement のアドレスを取得する つまりArray やStruct

    を操作する際に把握が必須 文字列はi8 のArray 。hello world するにはこいつが必要
  6. まずは LLVM IR で出力できるようにする まずは LLVM IR で出力できるようにする 拡張子はll 。test.ll

    とか作れば良い LLVM のツールチェーンであるlli を用いて実行すると楽 $ lli test.ll
  7. 多分の最小の構成 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*)
  8. 解説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 }
  9. 解説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
  10. 解説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*)
  11. 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 で考えてみる
  12. 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 }
  13. 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 }
  14. LLVM IR の GEP LLVM IR の GEP ; 型,

    型 変数, index1, index2, ...(以下状況 変更) getelementptr %[12 x i8], %[12 x i8]* %local_str, i32 0, i32 0 常にindex1 が0 にならない…?
  15. 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 }
  16. 作成する 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,
  17. 以下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
  18. お作法なので知ってしまえば簡単 お作法なので知ってしまえば簡単 // 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(), // 空文字 場合 勝手 変数名 生成 );
  19. まとめ 2 まとめ 2 LLVM-SYS.RS で LLVM IR を出力する意味はあるのか ?

    LLVM-SYS.RS で LLVM IR を出力する意味はあるのか ? あまりなさそう。Rust でLLVM IR を出力すれば良さそう な気はする しかしLLVM IR について知れたのは良いことなのでは? まぁその時楽しめれば良いよね
  20. 参考リンク 公式reference 公式のGetElementPtr の詳細な解説 ponyc のレポジトリ( 困ったら読む) The Architecture of

    Open Source Applications のLLVM Three-stage_compiler_structure きつねさんでもわかるLLVM