FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages

オリジナルLLVMバックエンド実装をまとめる(24. 末尾再帰関数呼び出しの実装2.)

前回の続き。末尾再帰の生成について。 LowerCallに戻る。IsTailCallがTrueとなり、末尾関数呼び出し最適化が有効として読み進める。 ... if (!IsTailCall) Chain = DAG.getCALLSEQ_START(Chain, NextStackOffset, 0, DL); ... 末尾関数呼び出し最適化が有効…

オリジナルLLVMバックエンド実装をまとめる(23. 末尾再帰関数呼び出しの実装1.)

関数呼び出しには様々な最適化の形があるが、その中の一つである末尾関数呼び出しでの最適化を実行してみる。 末尾関数呼び出しとは、ある関数f1()が関数f2()の最後の処理として呼び出されるケースを言う。 int f1(a, b) { a + b; } int f2(c, d, e, f) { /*…

オリジナルLLVMバックエンド実装をまとめる(22. 可変長引数をサポートするための処理)

C言語の可変長引数では、例えば以下のような記述が可能となる。 vararg.cpp #include <stdarg.h> int sum_i(int amount, ...) { int i = 0; int val = 0; int sum = 0; va_list vl; va_start(vl, amount); for (i = 0; i < amount; i++) { val = va_arg(vl, int); sum </stdarg.h>…

オリジナルLLVMバックエンド実装をまとめる(21. ByVal属性のついた引数を扱うための処理2)

前回の続き。 ByVal属性の引数における呼び出し側の処理 それでは、次に呼び出し側はどのようになっているのだろうか。 呼び出し側でも、ByVal属性のついた引数を一つ一つコピーして関数呼び出され側に渡す必要がある。 関数呼び出し側は、MYRISCVXTargetLow…

オリジナルLLVMバックエンド実装をまとめる(20. ByVal属性のついた引数を扱うための処理)

今までの関数処理の中で、引数は基本的にポインタか値渡し、そして値も何らかの型の値を1つずつ渡していくという形式だった。 しかし、C言語では構造体などの複数の要素をまとめた型を渡すことができる。また、C言語では構造体の値をそのまま値渡しで引数と…

オリジナルLLVMバックエンド実装をまとめる(19. LLVM IRからInstruction Selectionまでの流れ2)

前回の続き。 Legalizeでは、ターゲット固有のノードへの変換を行う。LLVM IRでは様々な演算ノードを定義しているが、ターゲットアーキテクチャによってはサポートしていない演算もある。 このような演算に関しては、ターゲットが生成できるノードに変換する…

オリジナルLLVMバックエンド実装をまとめる(18. LLVM IRからInstruction Selectionまでの流れ)

Instruction Selectionでは、LLVM IRを受け取り、それをSelection DAGに変換する。このフェーズは、さらに以下の細かなフェーズに分けることができる。 LLVM IRをSelection DAGへ変換 Selection DAGのCombine Selection DAGのLegalize Selection DAGをMachin…

オリジナルLLVMバックエンド実装をまとめる(17. 関数からも戻るときのCalling Convention)

次に、戻り値に関するCalling Conventionの実装から始める。 以下の記述では、関数の戻り値が渡される場合に、CCAssignToRegで示されるレジスタのどれかに引数が格納されるルールが追加されている。 そしてCalling ConventionであるRetCC_MYRISCVXを定義する…

オリジナルLLVMバックエンド実装をまとめる(16. 関数コールをサポートする)

今までのバックエンドの実装では、関数の取り扱いについていろいろとさぼっている部分があった。今回は、関数の定義と関数コールをきちんとサポートしようと思う。このためには、 スタックフレームの定義 引数の処理 などを実装していく。 現状では、引数の…

オリジナルLLVMバックエンド実装をまとめる(14. 分岐の際に発生する不要なジャンプを削除するPassの追加)

前回の制御構文を追加した際に、不要なジャンプ命令が発生しているのが気になった。例えば、LLVM IRをダンプし時に以下のようなIRが出力されたはずだ。 この時、br label %if.endはすぐ後ろのif.endにジャンプするため、このジャンプ文は不要なはずだ。ここ…

オリジナルLLVMバックエンド実装をまとめる(15. case文で使用されるJumpTableのサポート)

次は、if文を組み合わせたような形で登場するswitch文のサポートを考える。以下のようなコードを用意した。 test_switch.cpp int test_value = 0x30; // 0x30, 0x31, ... ,0x35 int a_val = 0; int b_val = 0; void test_switch () { int result = 0; switch…

オリジナルLLVMバックエンド実装をまとめる(14. 条件分岐命令の生成)

制御フロー生成 いよいよLLVMバックエンドの醍醐味、制御構文の生成に入る。 まずは、以下のような簡単なCプログラムをClangに入力し、LLVM IRを生成してみる。どのような制御IRが必要になるのかを確認する。 if_ctrl.cpp int test_ifctrl() { unsigned int …

オリジナルLLVMバックエンド実装をまとめる(13. 配列・構造体のサポートの確認)

配列のサポートの確認 次に、整数型以外に配列のサポートの確認をする。実は、ここまでの実装で配列はサポートできるようになっている。以下のプログラムをコンパイルしてみる。 int_arary.cpp int int_array() { int array[4] = {100, 200, 300, 400}; int …

オリジナルLLVMバックエンド実装をまとめる(12. int32以外の型のサポートの確認)

これまでの実装で、int型以外の型もサポートできているが、念のために確認しておく。 int32型よりも小さい型を扱うために、これまでに以下のノードを追加していたのだった。 llvm-myriscvx80/lib/Target/MYRISCVX/MYRISCVXInstrInfo.td // Load/Store PatFra…

オリジナルLLVMバックエンド実装をまとめる(11. グローバル変数の生成について)

今回は、グローバル変数を取り扱うための手法について調査する。 現状では、グローバル変数の入っているプログラムをコンパイルすると以下のようにエラーが発生する。 global_access.cpp int global0 = 0; int global1 = 100; void global_access () { int i…

コンピュータアーキテクチャ 定量的アプローチ(ヘネパタ) 第6版日本語版を購入

RISC-V Day Tokyo 2019でも販売したらしいのだが、参加しなかったのでネットで購入。 到着して、開封するととりあえずデカいな! コンピュータアーキテクチャ 第6版 原著と日本語版 中身はまだ熟読していないけど、とりあえず気になるのは2点: 表紙に「第6…

オリジナルLLVMバックエンド実装をまとめる(10. オブジェクトファイルの生成について)

オブジェクトファイルの生成 llcはアセンブリファイルを出力するだけでなく、オブジェクトファイルを出力する機能もある。オブジェクトファイルを出力するためには、llcのオプションで-filetype=asmの代わりに-filetype=objを指定する。 $ ./bin/llc -debug …

オリジナルLLVMバックエンド実装をまとめる(9. emitPrologue, emitEpilogueについて)

関数に関連する命令の生成の続き。関数のプロローグ・エピローグとはどのような処理をするのだろうか。 プロローグ : 関数の先頭で、関数のスタックフレームを生成する。関数が使用する変数のサイズだけスタックを移動し、メモリ領域を確保する。また、Calli…

オリジナルLLVMバックエンド実装をまとめる(8. メモリアクセス命令の生成について)

関数のプロローグ・エピローグでは、変数の取り扱いやスタックフレームの扱いなどでメモリアクセスが発生する。ここでは、これらの処理に必要なメモリアクセスの命令を追加する。 RISC-Vには、以下のメモリアクセス命令が定義されている。 さらに、RV64では…

オリジナルLLVMバックエンド実装をまとめる(7. 定数の生成について)

関数のプロローグ・エピローグに必要な新規命令の実装 関数のプロローグ・エピローグの処理に入る前に、少し新規命令を実装していく。これは、関数のプロローグ・エピローグの実装に際して必要なものだ。 定数生成パタンの実装 まずは最も基本的な定数を生成…

オリジナルLLVMバックエンド実装をまとめる(6. MYRISCVXのCalling Conventionについて)

命令セットアーキテクチャには、命令の定義ともに、関数呼び出しのルールを規定するCalling Conventionが定義されている。 MYRISCVXにもCalling Conventionが存在し、基本的にRISC-VのCalling Conventionに基づいている。このルールに基づき、引数を渡す際に…

オリジナルLLVMバックエンド実装をまとめる(5. LLVM IRのret文からreturn命令を生成するまでの流れ)

非常にシンプルな関数をどのようにして命令に変換するかについて考える。 int main() { return 0; } ./bin/clang -c -O2 ../myriscvx-tests/tests/simple_main.cpp -emit-llvm ./bin/llvm-dis simple_main.bc -o - define dso_local i32 @main() local_unnam…

Chisel-3.2 RC2でAsynchronous Resetを生成してみる

Chisel-3.2 RC2がリリースされている。いくつかの新機能が加わっているが、気になるのはAsynchronous Resetのサポートだ。 www.chisel-lang.org これだけ見ても良く分からないので、ChiselリポジトリのPull Requestを見て何となく使い方を調べてみた。 githu…

オリジナルLLVMバックエンド実装をまとめる(4. `ISelLowering`の初期実装とCalling Conventionの追加)

MYRISCVXISelLoweringはLLVM IRからSelectionDAG(データフローグラフ)への変換プロセスになる。バックエンドのかなり初期の部分で適用されます。 まずどのような変換処理から実装していけばよいだろうか?ここでは関数が呼ばれてから終了するまでの処理(main…

RISC-Vのベクトル拡張命令の仕様書を(ほぼ)日本語化したので公開する

というか昔からずっと昔から公開していたのだけれども、場所を全く公開していなかっただけで。 RISC-Vのベクトル拡張命令の仕様がかなり固まってきた。現在は0.7.1が公開されている。と思ったら以下のドキュメントをよく見てみると0.7.2に更新されているので…

NVDLA compilerがオープンソース化されたので試してみる(1. ビルド→失敗)

NVDLAというのはNVIDIAが公開しているオープンソースのディープラーニング向けハードウェアだが、このハードウェアで流すニューラルネットワークをコンパイルすることのできるコンパイラ nvdla_compiler がついにオープンソース化された。 nvdla_compilerは…

オリジナルLLVMバックエンド実装をまとめる(3. AsmPrinterとInstPrinterの役割)

MYRISCVXAsmPrinterはLLVM IR変換された命令の出力を司る。最終的な詳細の出力は後述するMYRISCVXInstPrinterクラスが実行するのだが、AsmPrinterはより高位なアセンブリ出力用のフレームワークとしての役割を果たす。 EmitInstruction() 具体的なアセンブリ…

LLVM 9.0.0がリリースされたのでRISC-Vの対応状況を確認する

LLVM 9.0.0がリリースされた。前回のリリースからおよそ半年である。最近はLLVMはリリースバージョンが半年に1回カウントアップするのでもう9.0まで到達している(もう少し小刻みでも良いのではないか...) LLVM 9.0のブランチはGitHubのLLVMリポジトリでも切…

オリジナルLLVMバックエンド実装をまとめる(2. llcがターゲットマシンを初期化するまでの流れ)

これまでに示した通り、LLVMにターゲットアーキテクチャを登録するためには様々な機能を追加する必要がある。 llcが呼ばれてから初期化プロセスがどこでどのようにして呼ばれているのか、追いかけてみることにする。 llcはllc.cppに定義されてあるmain()から…

オリジナルLLVMバックエンド実装をまとめる(1. クラス構造の関係図)

LLVMのバックエンドについて一通り勉強を進めてきたが、どうもまだしっくりこない部分がある。 もう少し各メソッドの構造についてサマライズし、いったいLLVMがどういう仕組みでバックエンドを出力しているのか、見ていきたい。 まずはここまでで、作成した…