きつねさんでもわかるLLVM読書会amagasaki.rb第5章

1,073 views
1,005 views

Published on

amagasaki.rbにて行われたきつねさんでもわかるLLVM読書会第二回 の資料です。フロントエンドの部分になります。

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,073
On SlideShare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
12
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

きつねさんでもわかるLLVM読書会amagasaki.rb第5章

  1. 1. きつねさんでもわかる LLVM読書会 第2回 7/5 tkuro11 13年7月6日土曜日
  2. 2. 自己紹介 • 最近(悪い意味で)世間をにぎわす   某半導体会社社員。 • 実はエンジニアじゃない • おてやわらかに。。。 tkuro11 13年7月6日土曜日
  3. 3. 祝単行本化 13年7月6日土曜日
  4. 4. きつねさんでもわかるLLVMの訂正一覧 貢献してます! 13年7月6日土曜日
  5. 5. 1ゲトー⊂(゚Д゚⊂͡`つ≡≡≡ズザーーーーーッ きつねさんでもわかるLLVMの訂正一覧 貢献してます! 13年7月6日土曜日
  6. 6. さて...... 13年7月6日土曜日
  7. 7. フロントエンドとは バッグ エンドA フロント エンド C バッグ エンドB フロント エンド Ruby A向け コード B向け コード Cソース rubyソース 言語依存 中間表現 ターゲット依存 13年7月6日土曜日
  8. 8. フロントエンドとは • 普通はソースコードから中間表現まで担当 • LLVMの場合 、バックエンドがLLVM-IR をいじり回すのでIRコード生成が中間表現 • 字句解析、構文解析、意味解析、コード生成 13年7月6日土曜日
  9. 9. フロントエンドとは • 普通はソースコードから中間表現まで担当 • LLVMの場合 、バックエンドがLLVM-IR をいじり回すのでIRコード生成が中間表現 • 字句解析、構文解析、意味解析、コード生成 LLVMっぽくなるのはここから 13年7月6日土曜日
  10. 10. DummyCCompiler • Cのサブセット • 全て int 型、他の型無 • グローバル変数無 • 変数の宣言時初期化無 • 変数のカンマ区切りの宣言無 • includeとかdefine無 • ビット演算無 • 単項演算無 • 配列のサポート無 https://github.com/Kmotiko/DummyCCompiler.git 13年7月6日土曜日
  11. 11. DummyCどんなん? i n t t e s t ( i n t j ) {   i n t i ;   i = j * 1 0 ;   r e t u r n i ; } i n t m a i n ( ) {   i n t i ;   i = 1 0 ;   t e s t ( i ) ;   r e t u r n 0 ; } わー貧弱 13年7月6日土曜日
  12. 12. DummyCどんなん? i n t t e s t ( i n t j ) {   i n t i ;   i = j * 1 0 ;   r e t u r n i ; } i n t m a i n ( ) {   i n t i ;   i = 1 0 ;   t e s t ( i ) ;   r e t u r n 0 ; } わー貧弱 13年7月6日土曜日
  13. 13. フロントエンドの流れ 字句解析 Lexer 構文解析 Parser 意味解析 Semantic Analysis 最適化 Optimizer コード生成 Code Generation ソース コード 13年7月6日土曜日
  14. 14. 234 字句解析 • 入力ソースコード → トークンの列 • まずは入れ物を用意 • Tokenクラス • TokenStreamクラス i n t u = 2 3 int ruby =4 ;r yb 13年7月6日土曜日
  15. 15. Tokenクラス • 保持すべきもの • 種類 • 文字列 • 数値 • 出現行数 列挙型のtypeで判別。継承にしてないのは コードふくれるから? 13年7月6日土曜日
  16. 16. TokenStreamクラス • Token追加 • Token取得 • カレント巻き戻し • カレント位置変更 • カレントの種類get • カレントの文字列get • カレントの数値get • Token出力(util) 13年7月6日土曜日
  17. 17. TokenStreamクラス bool applyTokenIndex(int index) {CurIndex=index;return true;} 微っっ妙・・・ bool getNextToken (); さらに微妙・・・ (ぶ、bool??????????) 13年7月6日土曜日
  18. 18. 字句解析 実装 • 方針としては • ifstreamで一行ずつread • 一文字ずつ読み込みトークン切り出し • Tokenインスタンス生成 -> TokenStreamに • 最後まで行ったらTokenStreamをreturn 13年7月6日土曜日
  19. 19. 字句解析 実装 • いきなりですがバグってます。 • コメントごときで死亡 •まあそれ以外は普通 • しかし++とかしすぎ(あちこちに状態変化) 13年7月6日土曜日
  20. 20. 構文解析 • Tokenから文法に従って AST (Abstract Syntax Tree)に。 • つまりはグループ化して後続段で使いやすく 234int ruby = 234ruby = int int 13年7月6日土曜日
  21. 21. 文法の定義 非終端記号 終端記号 13年7月6日土曜日
  22. 22. パーサの種類 • トップダウン(LL) • ボトムアップ(LR) こっから スタート CALL RET CALL CALL CALL RET RET RET スタックに記号と状態を積んでいく 解析表に従い右(R)がマッチングしたらreduceする(ポンっと消えてトップに近づく) E1 +2 E 13年7月6日土曜日
  23. 23. LR 13年7月6日土曜日
  24. 24. LR 13年7月6日土曜日
  25. 25. LR(k) LR(1) 構文解析 LALR(1) LL(k) SLR LR(0) LL(1) LL(0) パーサの種類 13年7月6日土曜日
  26. 26. LLの弱点 無限 ループ でござる 13年7月6日土曜日
  27. 27. isa<>とdyn_cast<> • ちょっとC++な内容 • C++の(つかいにくーい)RTTIの代わりに • isa<クラス>(instance) • dyn_cast<to class>(from class) • ベースclass -> 派生クラス変換(チェック つき) 13年7月6日土曜日
  28. 28. AST • 基底クラスを作る (BaseAST) • とみせかけて、なぜか列挙値によるID フィールドつき(isaあるのに・・・) 13年7月6日土曜日
  29. 29. 各ASTについて • リテラル • VariableAST, NumberAST • 二項演算子 • asignment_expression, additive_expression, multiplicative_expression = + * 13年7月6日土曜日
  30. 30. 各ASTについて • 変数宣言とジャンプ命令(return) • VariableDeclAST, JumpStmtAST • 関数とモジュール • FunctionAST, TranslationUnitAS • プロトタイプ宣言 • PrototypeAST veryトップ 13年7月6日土曜日
  31. 31. VariableDeclAST注意点 関数の引数は同じローカル変数でも初期値があるため区 別したかったらしい。 普通の変数もゼロ初期化にすりゃ良いのに 13年7月6日土曜日
  32. 32. 構文解析クラスの実装 • 戦略としては • ファイル名→ LexicalAnalysis() →TokenStream • 非終端記号ごとにfunctionを用意する • いわゆる再起下降パーサ • [コードを読む] 13年7月6日土曜日
  33. 33. 例 assign & primary expr 13年7月6日土曜日
  34. 34. 意味解析 • intしか無いので非常に簡単 • 実際、関数再定義の確認と、プロトタイプ とのパラメータの数しか見ていない。 • パースと同時に解析を行う 13年7月6日土曜日
  35. 35. コード生成 • ASTまでOK • ようやく...........!!! 13年7月6日土曜日
  36. 36. コード生成 • ASTまでOK • ようやく...........!!! LLVMたーいむ!!! 13年7月6日土曜日
  37. 37. コード生成 Module作成 Function作成 >> Moduleへ BasicBlock作成 >> Functionへ Instruction生成 >> BasicBlock 繰り返し 最後に出力 13年7月6日土曜日
  38. 38. コード生成 • 本来ならGlobalVariableも挿入するが DummyCには Global変数がない(!そうで した) • 該当するクラスを生成して作る • IRBuilderというお手軽便利クラスがある 13年7月6日土曜日
  39. 39. IRBuilder • llvm::IRBuilder(LLVMContext &C, MDNode *FPMathTag=0) • コンテキストはllvm::getGlobalContextで • テンプレート引数はいろいろ。よーわからん 13年7月6日土曜日
  40. 40. generateTranslationUnit • Moduleの作成 • プロトタイプと関数定義生成メソッドを呼び 出す • プロトタイプと関数定義はASTのトップに vector<>として入っている • [コード] 13年7月6日土曜日
  41. 41. generatePrototype • prototypeASTから Function生成 -> Module • ボディは生成しない • Functionに必要となる型情報は llvm::Typeの 関数から生成 • [コード] 13年7月6日土曜日
  42. 42. generateFunctionDefinition • generatePrototypeが作ったFunctionに命令を 入れるBasicBlockを追加 • BasicBlockはBasicBlock::Create()で生成 • その後、IRBuilderクラスのSetInsertPoint()で 命令の挿入位置(カーソルみたいな物)を指定 • [コード] 13年7月6日土曜日
  43. 43. generateFunctionStatement • 関数本体を生成 • FunctionStmtASTを り、変数定義、 Statement定義を行う • 実際に生成を行うのはこの下請けの generateVariableDeclarationと generateStatementになる 13年7月6日土曜日
  44. 44. generateVariableDeclaration • BasicBlockに変数宣言を追加 • Alloca命令の生成 : IRBuilderの CreateAlloca でイケる • (VariableASTの説明であった引数の初期)値の 書き込みはCreateStoreで。 • [コード] 13年7月6日土曜日
  45. 45. generateStatement • BaseASTの種類に応じてstatement生成 • 下請け関数に飛ばすだけ。 • isa<>のわかりやすい使用例 • ターンテーブル • [コード] 13年7月6日土曜日
  46. 46. generateBinaryExpression • 二項演算子コードの下請け • 左辺/右辺値のコード生成を再起 • 代入または四則演算 • ここにまたバグが!(0.9.2では直ってます) • [コード] 13年7月6日土曜日
  47. 47. generateCallExpression • 関数呼び出し命令を生成 • IRBuilder::CreateCall • 引数はvector<Value*>で与える • nameは返り値の名前になる • [コード] 13年7月6日土曜日
  48. 48. generateJmpStatement • return命令を生成 • IRBuilder::CreateRet • [コード] だんだんなげやりに・・・・ 13年7月6日土曜日
  49. 49. generateVariable • 変数参照を実装 . Load命令を生成する • IRBuilder::CreateLoad • [コード] だんだんやりなげに・・・・ 13年7月6日土曜日
  50. 50. だんだんやりなげに・・・・ generateNumber • 定数Valueを生成 • llvm::ConstantInt::get • [コード] 13年7月6日土曜日
  51. 51. だんだんやりなげに・・・・ generateNumber • 定数Valueを生成 • llvm::ConstantInt::get • [コード] 13年7月6日土曜日
  52. 52. おつかれ様でした • ありがとうございましたありがとうございました 13年7月6日土曜日
  53. 53. まだだ、まだ終わらんよ!!! 13年7月6日土曜日
  54. 54. main関数について • ドライバ部分が必要 ** gccみたいな • 短いので全部mainに書いちゃえ、という思想 らしい 13年7月6日土曜日
  55. 55. OptionParser • お手製getopt()/boost::program_options • なんでも自作好きだなー • 例によって結構強引 • [コード] 13年7月6日土曜日
  56. 56. 初期化とか • InitializeNativeTarget(); だったデータレイアウトはこれか! • sys::PrintStackTraceOnErrorSignal()名前通り • PrettyStackTraceProgram これも名前通り • EnableDebugBuffering = true; バッファのつじつまを合わせる? 13年7月6日土曜日
  57. 57. 出力の仕方 • パスマネージャに llvm::createPrintModulePass を登録→ pm.run()するだけ。 • ファイルオブジェクトは raw_fd_ostreamを使 う(これはエラー出力もパックしている) • 結構簡単。 13年7月6日土曜日
  58. 58. 初最適化(Passの指定) • さっきもやったけど基本的に パスマネー ジャに pm.add() するだけ。 • mem2reg をやってみる(足すだけ) • [コード] 13年7月6日土曜日
  59. 59. 組み込み関数(printnum) • どうせなので標準出力に出したい • 方針は Clangで吐いた目的コードを出して • Parserクラスにprintnum参照を追加 • リンクしてしまう • 結構な力技 13年7月6日土曜日
  60. 60. JIT • Just In Time • llvm::ExcuteEngineを利用(JIT専用ではない) • 実際にはサブクラスのllvm::Interpreter, llvm::JIT, llvm::MCJITのいずれかを利用 • MCはMachineCode 。in-memoryでよりアー キテクチャに近いコードのため、変換が速い 13年7月6日土曜日
  61. 61. ExecuteEngine • llvm::EngineBuilder::EngineBuilder(Mod) • そのあとcreate()メソッドを使用する • createが返した ExecutionEngine*が実行環境 の実体 • インクルードファイルで指定するか、または ExecusionEngine::setEngineKind() • MCの場合は setUseMCJITでも行ける 13年7月6日土曜日
  62. 62. JIT組み込み • doCodeGenで作ったModuleを ExecutionEngineに食わせる • ExecutionEngine::getPointerToFunctionにて 実行アドレスを取得。関数呼び出しでOK 13年7月6日土曜日
  63. 63. Metadata • Metadataには {MetadataString, MetadataNode} • MetadataString → llvm::MDString • MetadataNode → llvm::MDNode • MDBuilderを利用する 13年7月6日土曜日
  64. 64. Metadata • MDBuilderの生成メソッド MDString *createString(StringRef Str) MDNode *createFPMath(float Accuracy) MDNode *createRange(const APInt &Lo, const APInt &Hi) MDNode *createAnonymousTBAARoot() MDNode *createTBAARoot(StringRef Name) MDNode *createTBAANode(StringRef Name, MDNode *Parent, bool isConstant = false) MDNode *createTBAAStructNode(ArrayRef<TBAAStructField> Fields) MDNode *createBranchWeights(uint32_t TrueWeight, uint32_t FalseWeight) MDNode *createBranchWeights(ArrayRef<uint32_t> Weights) 13年7月6日土曜日
  65. 65. MDBuilderの使い方 • 生成したMDBuilderインスタンスを使って MDB->createFPMath(0.5); • のように使う • まあそのまま 13年7月6日土曜日
  66. 66. Metadataの反映 • 方法1:llvm::Instruction::setMetadataにて InstructionインスタンスにMetadataをひも付 け。 Stringか ID値にて登録できる • 方法2:IRBuilder経由で演算にひも付け 13年7月6日土曜日
  67. 67. Metadata • Metadataには {MetadataString, MetadataNode} • MetadataString → llvm::MDString • MetadataNode → llvm::MDNode 13年7月6日土曜日
  68. 68. CommandLine • ごめんなさいココロが・・・・ココロが折れ てしまいました。 13年7月6日土曜日
  69. 69. 13年7月6日土曜日
  70. 70. まとめ • フロントエンドの作成を説明 • 字句解析/構文解析/意味解析 • コード生成/JIT • 長かった。。。 • もっとツール使えバカ 13年7月6日土曜日
  71. 71. ありがとうございました ほんとうにおつかれさまでした 13年7月6日土曜日

×