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

71
きつねさんでもわかる LLVM読書会 第2回 7/5 tkuro11 1376日土曜日

description

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

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

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

きつねさんでもわかるLLVM読書会 第2回

7/5tkuro11

13年7月6日土曜日

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

自己紹介

•最近(悪い意味で)世間をにぎわす  某半導体会社社員。

•実はエンジニアじゃない

•おてやわらかに。。。

tkuro11

13年7月6日土曜日

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

祝単行本化

13年7月6日土曜日

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

きつねさんでもわかるLLVMの訂正一覧

貢献してます!

13年7月6日土曜日

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

1ゲトー⊂(゚Д゚⊂⌒`つ≡≡≡ズザーーーーーッ

きつねさんでもわかるLLVMの訂正一覧

貢献してます!

13年7月6日土曜日

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

さて......

13年7月6日土曜日

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

フロントエンドとは

バッグエンドA

フロントエンド

C

バッグエンドB

フロントエンド

Ruby

A向けコード

B向けコード

Cソース

rubyソース

言語依存

中間表現

ターゲット依存

13年7月6日土曜日

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

フロントエンドとは

• 普通はソースコードから中間表現まで担当

• LLVMの場合 、バックエンドがLLVM-IR

をいじり回すのでIRコード生成が中間表現

• 字句解析、構文解析、意味解析、コード生成

13年7月6日土曜日

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

フロントエンドとは

• 普通はソースコードから中間表現まで担当

• LLVMの場合 、バックエンドがLLVM-IR

をいじり回すのでIRコード生成が中間表現

• 字句解析、構文解析、意味解析、コード生成LLVMっぽくなるのはここから

13年7月6日土曜日

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

DummyCCompiler

• Cのサブセット

• 全て int 型、他の型無

• グローバル変数無

• 変数の宣言時初期化無

• 変数のカンマ区切りの宣言無

• includeとかdefine無

• ビット演算無

• 単項演算無

• 配列のサポート無

https://github.com/Kmotiko/DummyCCompiler.git

13年7月6日土曜日

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

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日土曜日

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

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日土曜日

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

フロントエンドの流れ

字句解析Lexer

構文解析Parser

意味解析SemanticAnalysis

最適化Optimizer

コード生成Code

Generation

ソースコード

13年7月6日土曜日

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

234

字句解析

• 入力ソースコード → トークンの列

• まずは入れ物を用意

• Tokenクラス

• TokenStreamクラス

i n tu

= 23 int ruby =4 ;r

yb

13年7月6日土曜日

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

Tokenクラス• 保持すべきもの

• 種類

• 文字列

• 数値

• 出現行数

列挙型のtypeで判別。継承にしてないのはコードふくれるから?

13年7月6日土曜日

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

TokenStreamクラス

• Token追加

• Token取得

• カレント巻き戻し

• カレント位置変更

• カレントの種類get

• カレントの文字列get

• カレントの数値get

• Token出力(util)

13年7月6日土曜日

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

TokenStreamクラスbool applyTokenIndex(int index){CurIndex=index;return true;}

微っっ妙・・・

bool getNextToken ();さらに微妙・・・ (ぶ、bool??????????)

13年7月6日土曜日

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

字句解析 実装• 方針としては

• ifstreamで一行ずつread

• 一文字ずつ読み込みトークン切り出し

• Tokenインスタンス生成 -> TokenStreamに

• 最後まで行ったらTokenStreamをreturn

13年7月6日土曜日

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

字句解析 実装

• いきなりですがバグってます。

• コメントごときで死亡•まあそれ以外は普通

• しかし++とかしすぎ(あちこちに状態変化)

13年7月6日土曜日

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

構文解析

• Tokenから文法に従って AST (Abstract Syntax Tree)に。

• つまりはグループ化して後続段で使いやすく

234int ruby =234ruby

=

int int

13年7月6日土曜日

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

文法の定義非終端記号 終端記号

13年7月6日土曜日

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

パーサの種類• トップダウン(LL)

• ボトムアップ(LR)

こっからスタート

CALL RET

CALL CALL

CALL

RET RET

RET

スタックに記号と状態を積んでいく

解析表に従い右(R)がマッチングしたらreduceする(ポンっと消えてトップに近づく)

E1 +2 E

13年7月6日土曜日

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

LR

13年7月6日土曜日

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

LR

13年7月6日土曜日

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

LR(k) LR(1)

構文解析

LALR(1)

LL(k)

SLR

LR(0)

LL(1)

LL(0)

パーサの種類

13年7月6日土曜日

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

LLの弱点

無限ループでござる

13年7月6日土曜日

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

isa<>とdyn_cast<>

• ちょっとC++な内容

• C++の(つかいにくーい)RTTIの代わりに

• isa<クラス>(instance)

• dyn_cast<to class>(from class)

• ベースclass -> 派生クラス変換(チェックつき)

13年7月6日土曜日

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

AST

• 基底クラスを作る (BaseAST)

• とみせかけて、なぜか列挙値によるIDフィールドつき(isaあるのに・・・)

13年7月6日土曜日

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

各ASTについて

• リテラル

• VariableAST, NumberAST

• 二項演算子

• asignment_expression, additive_expression, multiplicative_expression= + *

13年7月6日土曜日

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

各ASTについて• 変数宣言とジャンプ命令(return)

• VariableDeclAST, JumpStmtAST

• 関数とモジュール

• FunctionAST, TranslationUnitAS

• プロトタイプ宣言

• PrototypeAST

veryトップ

13年7月6日土曜日

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

VariableDeclAST注意点

関数の引数は同じローカル変数でも初期値があるため区別したかったらしい。普通の変数もゼロ初期化にすりゃ良いのに

13年7月6日土曜日

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

構文解析クラスの実装

• 戦略としては

• ファイル名→ LexicalAnalysis() →TokenStream

• 非終端記号ごとにfunctionを用意する

• いわゆる再起下降パーサ

• [コードを読む]

13年7月6日土曜日

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

例 assign & primary expr

13年7月6日土曜日

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

意味解析

• intしか無いので非常に簡単

• 実際、関数再定義の確認と、プロトタイプとのパラメータの数しか見ていない。

• パースと同時に解析を行う

13年7月6日土曜日

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

コード生成

• ASTまでOK

• ようやく...........!!!

13年7月6日土曜日

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

コード生成

• ASTまでOK

• ようやく...........!!!

LLVMたーいむ!!!13年7月6日土曜日

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

コード生成

Module作成

Function作成 >> Moduleへ

BasicBlock作成 >> Functionへ

Instruction生成 >> BasicBlock

繰り返し

最後に出力

13年7月6日土曜日

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

コード生成

• 本来ならGlobalVariableも挿入するがDummyCには Global変数がない(!そうでした)

• 該当するクラスを生成して作る

• IRBuilderというお手軽便利クラスがある

13年7月6日土曜日

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

IRBuilder

• llvm::IRBuilder(LLVMContext &C, MDNode *FPMathTag=0)

• コンテキストはllvm::getGlobalContextで

• テンプレート引数はいろいろ。よーわからん

13年7月6日土曜日

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

generateTranslationUnit

• Moduleの作成

• プロトタイプと関数定義生成メソッドを呼び出す

• プロトタイプと関数定義はASTのトップにvector<>として入っている

• [コード]

13年7月6日土曜日

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

generatePrototype

• prototypeASTから Function生成 -> Module

• ボディは生成しない

• Functionに必要となる型情報は llvm::Typeの関数から生成

• [コード]

13年7月6日土曜日

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

generateFunctionDefinition

• generatePrototypeが作ったFunctionに命令を入れるBasicBlockを追加

• BasicBlockはBasicBlock::Create()で生成

• その後、IRBuilderクラスのSetInsertPoint()で命令の挿入位置(カーソルみたいな物)を指定

• [コード]

13年7月6日土曜日

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

generateFunctionStatement

• 関数本体を生成

• FunctionStmtASTを辿り、変数定義、Statement定義を行う

• 実際に生成を行うのはこの下請けのgenerateVariableDeclarationとgenerateStatementになる

13年7月6日土曜日

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

generateVariableDeclaration

• BasicBlockに変数宣言を追加

• Alloca命令の生成 : IRBuilderの CreateAllocaでイケる

• (VariableASTの説明であった引数の初期)値の書き込みはCreateStoreで。

• [コード]

13年7月6日土曜日

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

generateStatement

• BaseASTの種類に応じてstatement生成

• 下請け関数に飛ばすだけ。

• isa<>のわかりやすい使用例

• ターンテーブル

• [コード]

13年7月6日土曜日

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

generateBinaryExpression

• 二項演算子コードの下請け

• 左辺/右辺値のコード生成を再起

• 代入または四則演算

• ここにまたバグが!(0.9.2では直ってます)

• [コード]

13年7月6日土曜日

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

generateCallExpression

• 関数呼び出し命令を生成

• IRBuilder::CreateCall

• 引数はvector<Value*>で与える

• nameは返り値の名前になる

• [コード]

13年7月6日土曜日

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

generateJmpStatement

• return命令を生成

• IRBuilder::CreateRet

• [コード]

だんだんなげやりに・・・・

13年7月6日土曜日

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

generateVariable

• 変数参照を実装 . Load命令を生成する

• IRBuilder::CreateLoad

• [コード]

だんだんやりなげに・・・・

13年7月6日土曜日

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

だんだんやりなげに・・・・

generateNumber

• 定数Valueを生成

• llvm::ConstantInt::get

• [コード]

13年7月6日土曜日

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

だんだんやりなげに・・・・

generateNumber

• 定数Valueを生成

• llvm::ConstantInt::get

• [コード]

13年7月6日土曜日

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

おつかれ様でした

• ありがとうございましたありがとうございました

13年7月6日土曜日

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

まだだ、まだ終わらんよ!!!13年7月6日土曜日

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

main関数について

• ドライバ部分が必要 ** gccみたいな

• 短いので全部mainに書いちゃえ、という思想らしい

13年7月6日土曜日

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

OptionParser

• お手製getopt()/boost::program_options

• なんでも自作好きだなー

• 例によって結構強引

• [コード]

13年7月6日土曜日

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

初期化とか • InitializeNativeTarget();

謎だったデータレイアウトはこれか!

• sys::PrintStackTraceOnErrorSignal()名前通り

• PrettyStackTraceProgram これも名前通り

• EnableDebugBuffering = true;

バッファのつじつまを合わせる?

13年7月6日土曜日

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

出力の仕方

• パスマネージャに llvm::createPrintModulePass を登録→

pm.run()するだけ。

• ファイルオブジェクトは raw_fd_ostreamを使う(これはエラー出力もパックしている)

• 結構簡単。

13年7月6日土曜日

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

初最適化(Passの指定)

• さっきもやったけど基本的に パスマネージャに pm.add() するだけ。

• mem2reg をやってみる(足すだけ)

• [コード]

13年7月6日土曜日

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

組み込み関数(printnum)

• どうせなので標準出力に出したい

• 方針は Clangで吐いた目的コードを出して

• Parserクラスにprintnum参照を追加

• リンクしてしまう

• 結構な力技

13年7月6日土曜日

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

JIT

• Just In Time

• llvm::ExcuteEngineを利用(JIT専用ではない)

• 実際にはサブクラスのllvm::Interpreter, llvm::JIT, llvm::MCJITのいずれかを利用

• MCはMachineCode 。in-memoryでよりアーキテクチャに近いコードのため、変換が速い

13年7月6日土曜日

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

ExecuteEngine

• llvm::EngineBuilder::EngineBuilder(Mod)

• そのあとcreate()メソッドを使用する

• createが返した ExecutionEngine*が実行環境の実体

• インクルードファイルで指定するか、またはExecusionEngine::setEngineKind()

• MCの場合は setUseMCJITでも行ける13年7月6日土曜日

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

JIT組み込み

• doCodeGenで作ったModuleを ExecutionEngineに食わせる

• ExecutionEngine::getPointerToFunctionにて実行アドレスを取得。関数呼び出しでOK

13年7月6日土曜日

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

Metadata

• Metadataには {MetadataString, MetadataNode}

• MetadataString → llvm::MDString

• MetadataNode → llvm::MDNode

• MDBuilderを利用する

13年7月6日土曜日

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

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日土曜日

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

MDBuilderの使い方

• 生成したMDBuilderインスタンスを使って MDB->createFPMath(0.5);

• のように使う

• まあそのまま

13年7月6日土曜日

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

Metadataの反映

• 方法1:llvm::Instruction::setMetadataにてInstructionインスタンスにMetadataをひも付け。 Stringか ID値にて登録できる

• 方法2:IRBuilder経由で演算にひも付け

13年7月6日土曜日

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

Metadata

• Metadataには {MetadataString, MetadataNode}

• MetadataString → llvm::MDString

• MetadataNode → llvm::MDNode

13年7月6日土曜日

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

CommandLine

• ごめんなさいココロが・・・・ココロが折れてしまいました。

13年7月6日土曜日

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

13年7月6日土曜日

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

まとめ

• フロントエンドの作成を説明

• 字句解析/構文解析/意味解析

• コード生成/JIT

• 長かった。。。

• もっとツール使えバカ

13年7月6日土曜日

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

ありがとうございましたほんとうにおつかれさまでした

13年7月6日土曜日