write-your-llvm-backend/main.asciidoc
Ushitora Anqou b7b45b3016 update
2020-03-31 22:18:44 +09:00

832 lines
50 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

= 手を動かせばできるLLVMバックエンド チュートリアル
艮 鮟鱇 <ushitora@anqou.net>
:toc: left
:icons: font
:stem: latexmath
== FIXME
AsciiDocのコメントを用いて文中にFIXMEを仕込む。
その他のFIXME全般的なものなどをここにリストにする。
* だ・である調をです・ます調に変える。
* 実際にやってみる。
** 現状過去の作業ログを切り貼りしながら書いているので通してちゃんと動くかは良くわからない。
** ついでにLLVM v10.0.0に対応させる。
== この文書について
この文書はhttps://asciidoctor.org/[Asciidoctor]を用いて執筆されています。
記述方法はhttps://asciidoctor.org/docs/user-manual/[Asciidoctor User Manual]を
参考にしてください。
この文書はGitによって管理されています。
https://github.com/ushitora-anqou/write-your-llvm-backend[リポジトリはGitHubにて
公開しています]。
この文書におおよそ則って開発されたLLVMバックエンドのソースコードを
https://github.com/virtualsecureplatform/llvm-cahp[GitHubリポジトリにて公開しています]。
この作品は、クリエイティブ・コモンズの 表示 4.0 国際 ライセンスで提供されています。ライセンスの写しをご覧になるには、 http://creativecommons.org/licenses/by/4.0/ をご覧頂くか、Creative Commons, PO Box 1866, Mountain View, CA 94042, USA までお手紙をお送りくださいfootnote:[この
段落はクリエイティブ・コモンズより引用。]。
本文書の内容は筆者が独自に調査したものです。
**疑う余地なく誤りが含まれます**。誤りに気づかれた方はGitHubリポジトリなどを通じて
ご連絡ください。なお誤っていそうな部分についてはAsciidoctorのコメント機能を用いて
コメントを残しています。 `FIXME` というキーワードでソースコードの全文検索をしてください。
== LLVMバックエンド概略
本書ではRISC-V風味の独自ISAを例にLLVMバックエンドを開発します。
// FIXME: そのうち10がでそう。
使用するLLVMのバージョンはv9.0.0です。
// FIXME: 人がLLVMバックエンドを書きたくなるような文章をここに書く。
== ところで
一度もコンパイラを書いたことがない人は、この文書を読む前に
『低レイヤを知りたい人のためのCコンパイラ作成入門』<<rui-compilerbook>>などで一度
フルスクラッチからコンパイラを書くことをおすすめします。
また<<krister-writing_gcc_backend>>などを参考に、
LLVMではなくGCCにバックエンドを追加することも検討してみてはいかがでしょうか。
== 参考にすべき文献
LLVMバックエンドを開発する際に参考にできる書籍やWebサイトを以下に一覧します。
なおこの文書では、RISC-Vバックエンド及びそれに関する技術資料を**大いに**参考しています。
=== Webページ
* Writing an LLVM Backend<<llvm-writing_backend>>
** 分かりにくく読みにくい。正直あんまり見ていないが、たまに眺めると有益な情報を見つけたりもする。
* The LLVM Target-Independent Code Generator<<llvm-code_generator>>
** <<llvm-writing_backend>>よりもよほど参考になる。LLVMバックエンドがどのようにLLVM IRをアセンブリに落とすかが明記されている。必読。
* TableGenのLLVMのドキュメント<<llvm-tablegen>>
** 情報量が少ない。これを読むよりも各種バックエンドのTableGenファイルを読むほうが良い。
* LLVM Language Reference Manual<<llvm-langref>>
** LLVM IRについての言語リファレンス。LLVM IRの仕様などを参照できる。必要に応じて読む。
* Architecture & Platform Information for Compiler Writers<<llvm-compilerwriterinfo>>
** LLVMで公式に実装されているバックエンドに関するISAの情報が集約されている。Lanaiの言語仕様へのリンクが貴重。
* RISC-V support for LLVM projects<<github_riscv-llvm>>
** **どちゃくそに参考になる**。以下の開発はこれに基づいて行う。
** LLVMにRISC-Vサポートを追加するパッチ群。バックエンドを開発するためのチュートリアルも兼ねているらしく `docs/` 及びそれと対応したpatchが参考になる。
** またこれについて、開発者が2018 LLVM Developers' Meetingで登壇したときの動画は<<youtube_llvm-backend-development-by-example>>より閲覧できる。スライドは<<speakerdeck-llvm_backend_development>>より閲覧できる。
** そのときのCoding Labは<<lowrisc-devmtg18>>より閲覧できる。
* Create an LLVM Backend for the Cpu0 Architecture<<cpu0>>
** Cpu0という独自アーキテクチャのLLVMバックエンドを作成するチュートリアル。多少古いが、内容が網羅的で参考になる。英語が怪しい。
* FPGA開発日記<<fpga_develop_diary>>
** Cpu0の資料<<cpu0>>をもとに1からRISC-Vバックエンドを作成する過程がブログエントリとして公開されている。GitHubに実装も公開されている<<fpga_develop_diary-llvm>>。
* ELVMバックエンド<<elvm-llvm_backend>>
** 限られた命令でLLVM IRの機能を達成する例として貴重。でも意外とISAはリッチだったりする。
** 作成者のスライドも参考になる<<elvm-slide>>。
* 2018年度東大CPU実験で開発されたLLVM Backend<<todai_llvm_backend>>
** これについて書かれたAdCのエントリもある<<todai_llvm_backend-article>>。
* Tutorial: Building a backend in 24 hours<<llvm-anton_korobeynikov_2012>>
** LLVMバックエンドの大まかな動きについてざっとまとめたあと、 `ret` だけが定義された最低限のLLVMバックエンド ("stub backend") を構成している。
** Instruction Selection の説明にある *Does bunch of magic and crazy pattern-matching* が好き。
* 2017 LLVM Developers Meeting: M. Braun "Welcome to the back-end: The LLVM machine representation"<<llvm-welcome_to_the_back_end_2017>>
** スライドも公開されている<<welcome_to_the_back_end-slides>>。
** 命令選択が終わったあとの中間表現であるLLVM MIR
`MachineFunction` や `MachineInstr` など)や、それに対する操作の解説。
RegStateやframe index・register scavengerなどの説明が貴重。
* Howto: Implementing LLVM Integrated Assembler<<ean10-howto-llvmas>>
** LLVM上でアセンブラを書くためのチュートリアル。アセンブラ単体に焦点を絞ったものは珍しい。
* Building an LLVM Backend<<LLVMBackend_2015_03_26_v2>>
** 対応するレポジトリが<<github-frasercrmck_llvm_leg>>にある。
* [LLVMdev] backend documentation<<llvm_dev_ml-059799>>
** llvm-devメーリングリストのバックエンドのよいドキュメントは無いかというスレッド。Cpu0とTriCoreが挙げられているが、深くまで記述したものは無いという回答。
* TriCore Backend<<tricore-llvm>>
** TriCoreというアーキテクチャ用のバックエンドを書いたという論文。スライドもある<<tricore-llvm-slides>>。ソースコードもGitHub上に上がっているが、どれが公式かわからないfootnote:[論文とスライドも怪しいものだが、著者が一致しているので多分正しいだろう。]。
* Life of an instruction in LLVM<<life_of_an_instruction>>
** Cコードからassemblyまでの流れを概観。
* LLVM Backendの紹介<<llvm_backend_intro>>
** 「コンパイラ勉強会」footnote:[これとは別の発表で「コンパイラ開発してない人生はFAKE」という名言が飛び出した勉強会<<compiler_study_report>>。]での、LLVMバックエンドの大きな流れ特に命令選択について概観した日本語スライド。
=== 書籍
* 『きつねさんでもわかるLLVM〜コンパイラを自作するためのガイドブック〜』<<fox-llvm>>
** 数少ない日本語資料。Passやバックエンドの各クラスについて説明している。<<llvm-code_generator>>と合わせて大まかな流れを掴むのに良い。
** ただし書籍中で作成されているバックエンドは機能が制限されており、またコードベースも多少古い。
なおLLVMについてGoogleで検索していると"LLVM Cookbook"なる謎の書籍(の電子コピー)が
見つかるが、内容はLLVM公式文書のパクリのようだ<<amazon-llvm_cookbook-customer_review>>。
=== バックエンド
* RISC-V<<riscv>>
** パッチ群が開発ドキュメントとともに公開されている<<github_riscv-llvm>>。以降の開発はこれをベースに行う。
* Lanai<<lanai-isa>>
** Googleが開発した32bit RISCの謎アーキテクチャ。全く実用されていないが、バックエンドが単純に設計されておりコメントも豊富のためかなり参考になるfootnote:[LLVMバックエンドの開発を円滑にするためのアーキテクチャなのではと思うほどに分かりやすい。]footnote:[後のSparcについて<<llvm_dev_ml-059799>>
にて指摘されているように、商業的に成功しなかったバックエンドほどコードが単純で分かりやすい。]。
* Sparc
** <<llvm-writing_backend>>でも説明に使われており、コメントが豊富。
* x86
** みんな大好きx86。貴重なCISCの資料であり、かつ2オペランド方式を採用する場合に実装例を与えてくれる。あと `EFLAGS` の取り回しなども参考になるが、全体的にコードは読みにくい。ただLLVMの命名規則には従うため、他のバックエンドからある程度推論をして読むのが良い。
== ISAの仕様を決める
本書で使用するISAであるCAHPv3について説明します。
cahpv3.pdfを参考のこと。
// FIXME: 書く
== スケルトンバックエンドを追加する
https://github.com/virtualsecureplatform/llvm-cahp/commit/d0b8dd14570dc9efac09d3c5fd6e8512980fd7b7[d0b8dd14570dc9efac09d3c5fd6e8512980fd7b7]
CAHPのためのビルドを行うために、中身のないバックエンドスケルトンバックエンド
LLVMに追加します。
=== CAHPをTripleに追加する
<<github_riscv-llvm_docs_02>>を参考にして
CAHPをLLVMに認識させます。LLVMではコンパイル先のターゲットをTripleという単位で
管理しています。そのTripleの一つとしてCAHPを追加します。
`llvm/include/llvm/ADT/Triple.h` や `llvm/lib/Support/Triple.cpp` などの
ファイルにTripleが列挙されているため、そこにCAHPを追加します。
また `llvm/unittests/ADT/TripleTest.cpp` にTripleが正しく認識されているかをチェックする
テストを書きます。
=== CAHPのELFフォーマットを定義する
<<github_riscv-llvm_patch_03>>を参考にして、CAHPのためのELFフォーマットを定義します。
具体的にはCAHPのマシンを表す識別コードや再配置情報などを記述し、
ELFファイルの出力が動作するようにします。
ただし独自ISAではそのような情報が決まっていないため、適当にでっちあげます。
=== バックエンドを追加する
<<github_riscv-llvm_patch_04>>を参考に `llvm/lib/Target` ディレクトリ内に
`CAHP` ディレクトリを作成し、最低限必要なファイルを用意します。
まずビルドのために `CMakeLists.txt` と `LLVMBuild.txt` を用意します。
またCAHPに関する情報を提供するために
`CAHPTargetInfo.cpp` や `CAHPTargetMachine.cpp` などを記述します。
`CAHPTargetMachine.cpp` ではdata layoutを文字列で指定します。
詳細はLLVM IRの言語仕様<<llvm-langref-datalayout>>を参考してください。
// FIXME: ここで指定するdata layoutが結局の所どの程度影響力を持つのかは良くわからない。
// ツール間でのターゲットの識別程度にしか使ってなさそう。要確認。
以上で必要最小限のファイルを用意することができました。
== LLVMをビルドする
LLVMは巨大なプロジェクトで、ビルドするだけでも一苦労です。
以下では継続的な開発のために、高速にLLVMをデバッグビルドする手法を紹介します。
<<github_riscv-llvm_docs_01>>・<<llvm_getting-started>>・<<clang_gettings-started>>を
参考にしています。
ビルドの際には以下のソフトウェアが必要になります。
* `cmake`
* `ninja`
* `clang`
* `clang++`
* `lld`
まずLLVMのソースコードをGitを用いて取得します。
前述したように、今回の開発ではLLVM v9.0.0をベースとします。
そこでブランチ `llvmorg-9.0.0` から独自実装のためのブランチ `cahp` を生成し、
以降の開発はこのブランチ上で行うことにします。
$ git clone https://github.com/llvm/llvm-project.git
$ cd llvm-project
$ git switch llvmorg-9.0.0
$ git checkout -b cahp
続いて、ビルドを行うための設定をCMakeを用いて行います。
大量のオプションはビルドを早くするためのものです<<llvm_dev_ml-106187>>。
$ mkdir build
$ cd build
$ cmake -G Ninja \
-DLLVM_ENABLE_PROJECTS="clang;lld" \
-DCMAKE_BUILD_TYPE="Debug" \
-DBUILD_SHARED_LIBS=True \
-DLLVM_USE_SPLIT_DWARF=True \
-DLLVM_OPTIMIZED_TABLEGEN=True \
-DLLVM_BUILD_TESTS=True \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DLLVM_USE_LINKER=lld \
-DLLVM_TARGETS_TO_BUILD="" \
-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD="CAHP" \
../llvm
Ninjaを用いてビルドを行います。直接Ninjaを実行しても構いません `$ ninja` )が、
CMakeを用いて間接的に実行することもできます。
$ cmake --build .
手元の環境CPUはIntel Core i7-8700で6コア12スレッド、RAMは16GBでは
30分弱でビルドが完了しました。
また別の環境CPUはIntel Core i5-7200Uで2コア4スレッド、RAMは8GBでは
1時間半程度かかりました。以上から類推すると、
stem:[n]コアのCPUを使用する場合およそstem:[\frac{180}{n}]分程度かかるようです。
ビルドが終了すると `bin/` ディレクトリ以下にコンパイルされたバイナリが生成されます。
例えば次のようにして、CAHPバックエンドが含まれていることを確認できます。
....
$ bin/llc --version
LLVM (http://llvm.org/):
LLVM version 9.0.0
DEBUG build with assertions.
Default target: x86_64-unknown-linux-gnu
Host CPU: skylake
Registered Targets:
cahp - CAHP
....
[NOTE]
====
ここでは開発用にデバッグビルドを行いました。
一方で、他人に配布する場合などはリリースビルドを行います。
その際は次のようにCMakeのオプションを指定します。
// FIXME: LLVM_BUILD_TESTS=False で良い気がする。要確認。
$ cmake -G Ninja \
-DLLVM_ENABLE_PROJECTS="lld;clang" \
-DCMAKE_BUILD_TYPE="Release" \
-DLLVM_BUILD_TESTS=True \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DLLVM_USE_LINKER=lld \
-DLLVM_TARGETS_TO_BUILD="" \
-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD="CAHP" \
../llvm
====
== LLVMをテストする
`llvm-lit` を使用してLLVMをテストできます。
$ bin/llvm-lit test -s # 全てのテストを実行する。
$ bin/llvm-lit -s --filter "Triple" test # Tripleに関するテストを実行する。
$ bin/llvm-lit -s --filter 'CAHP' test # CAHPを含むテストを実行する。
$ bin/llvm-lit -as --filter 'CAHP' test # テスト結果を詳細に表示する。
$ bin/llvm-lit -as --filter 'CAHP' --debug test # デバッグ情報を表示する。
== アセンブラを作る
https://github.com/virtualsecureplatform/llvm-cahp/commit/2c31c0a80020cc50bba6df1c35da228905190d97[2c31c0a80020cc50bba6df1c35da228905190d97]
この章ではLLVMバックエンドの一部としてアセンブラを実装します。
具体的にはLLVMのMCLayerを実装し、アセンブリからオブジェクトファイルへの変換を可能にします。
一度にアセンブラ全体を作るのは難しいため、まずレジスタのみを使用する演算命令に絞って実装し、
その後メモリを使用する命令をカバーします。
=== TableGenファイルを追加する
LLVM coreは基本的に{cpp}によって記述されています。一方で、多くの箇所で共通する処理などは
独自のDSLドメイン固有言語であるTableGenを用いて記述し `llvm-tblgen` という
ソフトウェアを用いてこれを{cpp}コードに変換しています。
こうすることによって記述量を減らし、ヒューマンエラーを少なくするという考え方
のようです<<llvm-tablegen>>。
LLVMバックエンドでは、アーキテクチャが持つレジスタや命令などの情報をTableGenによって
記述します。大まかに言って、TableGenで書ける場所はTableGenによって書き、
対応できない部分を{cpp}で直に書くというのがLLVM coreの方針のようです。
// FIXME: 単なる印象。ほんまか?
ここでは、簡単なアセンブラを実装するために最低限必要なTableGenファイルを追加します。
内訳は次のとおりです。
* `CAHP.td`: 下のTableGenファイルをincludeし、その他もろもろを定義。
* `CAHPRegisterInfo.td`: レジスタを定義。
* `CAHPInstrFormats.td`: 命令形式を定義。
* `CAHPInstrInfo.td`: 命令を定義。
順に説明します。 `CAHP.td` がTableGenファイル全体をまとめているTableGenファイルで、
内部では `include` を使って他のファイルを読み込んでいます。
include "llvm/Target/Target.td"
include "CAHPRegisterInfo.td"
include "CAHPInstrInfo.td"
また同時に、今回想定するプロセッサを表す `ProcessorModel` や、
現在実装しているターゲットの `CAHP` について定義しています。
// FIXME: ここの定義が具体的にC++コードにどう反映されるかの確認が必要。
// まぁこう書いておけば問題ないという認識でもとりあえず良い気もするけど……。
`CAHPRegisterInfo.td` ではCAHPに存在するレジスタを定義します。
まず `Register` を継承して `class CAHPReg` を作り、これに基本的なレジスタの性質をもたせます。
ついで `class CAHPReg` の実体として `X0` から `X15` を作成します。
`alt` にはレジスタの別名を指定します。
// FIXME: ABIRegAltName がどういう役割を果たしてるのか要検証。
// 多分 `getRegisterName` の第二引数に何も渡さなかったときにAltNameを表示
// させるのに必要なんだと思うけど、裏をとってない。
最後に、レジスタをまとめて `RegisterClass` である `GPR`
General Purpose Register; 汎用レジスタの意)を定義します。
このあと命令を定義する際にはこの `RegisterClass` 単位で指定します。
ここでレジスタを並べる順番が先であるほどレジスタ割り付けで割り付けられやすいため、
caller-savedなもの使ってもspill outが起こりにくいものを先に並べておきます。
`GPR` と同様に `SP` という `RegisterClass` も作成し、 `X1` 、
つまりスタックポインタを表すレジスタのみを追加しておきます。
この `RegisterClass` を命令のオペランドに指定することで
`lwsp` や `swsp` などの「スタックポインタのみを取る命令」を表現することができます。
命令は `CAHPInstrFormats.td` と `CAHPInstrInfo.td` に分けて記述します。
`CAHPInstrFormats.td` ではおおよその命令の「形」を定義しておき、
`CAHPInstrInfo.td` でそれを具体化します。言葉で言ってもわかりにくいので、コードで見ます。
例えば24bit長の加算命令は次のように定義されます。
まずCAHPの命令全体に共通する事項を `class CAHPInst` として定義します。
....
class CAHPInst<dag outs, dag ins, string opcodestr, string argstr, list<dag> pattern = []>
: Instruction {
let Namespace = "CAHP";
dag OutOperandList = outs;
dag InOperandList = ins;
let AsmString = opcodestr # "\t" # argstr;
// Matching patterns used when converting SelectionDAG into MachineDAG.
let Pattern = pattern;
}
....
次に、CAHPの24bit命令に共通する事項を `class CAHPInst` を継承した
`class CAHP24Inst` として定義します。
....
// 24-bit instruction format.
class CAHPInst24<dag outs, dag ins, string opcodestr, string argstr, list<dag> pattern = []>
: CAHPInst<outs, ins, opcodestr, argstr, pattern> {
let Size = 3;
bits<24> Inst;
}
....
さらに、24bit長加算命令の「形」である24bit R形式オペランドにレジスタを3つとる
`class CAHPInst24R` として定義します。 `class CAHPInst24` を継承します。
....
// 24-bit R-instruction format.
class CAHPInst24R<bits<8> opcode, dag outs, dag ins, string opcodestr, string argstr>
: CAHPInst24<outs, ins, opcodestr, argstr> {
bits<4> rd;
bits<4> rs1;
bits<4> rs2;
let Inst{23-20} = 0;
let Inst{19-16} = rs2;
let Inst{15-12} = rs1;
let Inst{11-8} = rd;
let Inst{7-0} = opcode;
}
....
最後にこれを使って加算命令 `ADD` を定義します。
....
def ADD : CAHPInst24R<0b00000001, (outs GPR:$rd), (ins GPR:$rs1, GPR:$rs2),
"add", "$rd, $rs1, $rs2">;
....
上記の継承による構造を展開すると、結局 `class Instruction` を使って
次のような定義を行ったことになります。
// FIXME: 要確認。
....
def ADD : Instruction {
let Namespace = "CAHP";
let Pattern = [];
let Size = 3; // 命令長は8bit * 3 = 24bit
bits<24> Inst;
bits<4> rd; // オペランドrdは4bit
bits<4> rs1; // オペランドrs1は4bit
bits<4> rs2; // オペランドrs2は4bit
// 命令のエンコーディングは次の通り。
let Inst{23-20} = 0; // 20〜23bit目は0
let Inst{19-16} = rs2; // 16〜19bit目はrs2
let Inst{15-12} = rs1; // 12〜15bit目はrs1
let Inst{11-8} = rd; // 8〜11bit目はrd
let Inst{7-0} = 0b00000001; // 0〜7bit目は0bit目だけが1で残りは0
// 出力はレジスタクラスGPRのrdに入る。
dag OutOperandList = (outs GPR:$rd);
// 入力はレジスタクラスGPRのrs1とrs2に入る。
dag InOperandList = (ins GPR:$rs1, GPR:$rs2);
// アセンブリ上では「add rd, rs1, rs2」という形で与えられる。
let AsmString = "add\t$rd, $rs1, $rs2";
}
....
// FIXME: `AsmString` は出力とパーズの両方に使われるっぽい。要確認。
`Inst` フィールドにエンコーディングを設定することで、
TableGenにエンコードの処理を移譲することができますfootnote:[一方でx86など
複雑なエンコーディングを行うISAの場合は `Inst` フィールドを使用せず、
自前で変換を行っている。]。
続いて即値を用いる命令を見ます。例として `addi` を取り上げます。
`addi` は8bit符号付き即値をオペランドに取ります。まずこれを定義します。
class ImmAsmOperand<string prefix, int width, string suffix> : AsmOperandClass {
let Name = prefix # "Imm" # width # suffix;
let RenderMethod = "addImmOperands";
let DiagnosticType = "Invalid" # Name;
}
class SImmAsmOperand<int width, string suffix = "">
: ImmAsmOperand<"S", width, suffix> {
}
def simm8 : Operand<i16> {
let ParserMatchClass = SImmAsmOperand<8>;
}
続いて命令の「形」を定義します。 `addi` は24bit I形式です。
....
class CAHPInst24I<bits<8> opcode, dag outs, dag ins, string opcodestr, string argstr>
: CAHPInst24<outs, ins, opcodestr, argstr> {
bits<4> rd;
bits<4> rs1;
bits<8> imm;
let Inst{23-16} = imm;
let Inst{15-12} = rs1;
let Inst{11-8} = rd;
let Inst{7-0} = opcode;
}
....
最後に、これを用いて `addi` を定義します。
def ADDI : CAHPInst24I<0b11000011, (outs GPR:$rd), (ins GPR:$rs1, simm8:$imm),
"addi", "$rd, $rs1, $imm">;
`add` の際には `GPR` とした第三オペランドが `simm8` となっています。
これによって、この部分に符号付き8bit即値が来ることを指定しています。
即値のうち、下位1bitが0になるものは `_lsb0` というサフィックスを名前につけ区別しておきます。
`uimm7_lsb0` と `simm11_lsb0` がそれに当たります。
後々、{cpp}コードにてこの制限が守られているかをチェックします。
`add2` のような2オペランドの命令を記述する場合、上の方法では問題があります。
というのも `add2` の第一オペランドは入力であると同時に出力先でもあるためです。
// FIXME: 要検証outsとinsに同じレジスタを指定した場合はエラーになる
このような場合は次のように `Constraints` フィールドにその旨を記述します。
let Constraints = "$rd = $rd_w" in {
def ADD2 : CAHPInst16R<0b10000000, (outs GPR:$rd_w), (ins GPR:$rd, GPR:$rs),
"add2", "$rd, $rs">;
}
なおTableGenでは `let` で囲むレコードが一つの場合は括弧 `{ }` は必要ありません。
また `let` で外からフィールドを上書きするのと、 `def` の中身に記載するのとで意味は
変わりません。すなわち、上のコードは次の2通りと意味は異なりません<<llvm-tablegen>>。
// FIXME: 要検証:本当に意味が変わらないか
let Constraints = "$rd = $rd_w" in
def ADD2 : CAHPInst16R<0b10000000, (outs GPR:$rd_w), (ins GPR:$rd, GPR:$rs),
"add2", "$rd, $rs">;
def ADD2 : CAHPInst16R<0b10000000, (outs GPR:$rd_w), (ins GPR:$rd, GPR:$rs),
"add2", "$rd, $rs"> {
let Constraints = "$rd = $rd_w";
}
必要なTableGenファイルを追加した後、
これらのTableGenファイルが正しいかどうか `llvm-tblgen` を用いて確認します。
// FIXME: 要検証:ここで表示されるのは継承を展開したものになっているはず。
// どのへんをみて「正しい」と判断するのか。
$ bin/llvm-tblgen -I ../llvm/lib/Target/CAHP/ -I ../llvm/include/ -I ../llvm/lib/Target/ ../llvm/lib/Target/CAHP/CAHP.td
// FIXME: 要確認キーワードfieldがつく場合とつかない場合で意味が異なるか。
// 観測範囲で言うと多分変わらない。
=== `MCTargetDesc` を追加する
アセンブラ本体の{cpp}コードを作成します。ここでは、
アセンブリのエンコードからバイナリ生成部分を担当する `MCTargetDesc` ディレクトリを追加し、
必要なファイルを揃えます。複数のクラスを定義しますが、それらは全て
`MCTargetDesc/CAHPMCTargetDesc.cpp` にある `LLVMInitializeCAHPTargetMC`
関数でLLVM coreに登録されます。
定義するクラスは次のとおりです。
* `CAHPMCAsmInfo`
* `CAHPMCInstrInfo`
* `CAHPMCRegisterInfo`
* `CAHPMCSubtargetInfo`
* `CAHPMCCodeEmitter`
* `CAHPAsmBackend`
* `CAHPELFObjectWriter`
順に説明します。
`CAHPMCAsmInfo` にはアセンブリがどのように表記されるかを主に記述します。
// FIXME: 要確認とllvm::MCAsmInfoのコメントにも書いてあるんだけど、
// の割にCalleeSaveStackSlotSizeとかCodePointerSizeとか指定してて
// どういうこっちゃとなる。
`MCTargetDesc/CAHPMCAsmInfo.{h,cpp}` に記述します。
`CAHPMCInstrInfo` は先程記述したTableGenファイルから、
TableGenによって `InitCAHPMCInstrInfo` 関数として自動的に生成されます。
`CAHPMCTargetDesc.cpp` 内でこれを呼び出して作成します。
`CAHPMCRegisterInfo` も同様に自動的に生成されます。
`InitCAHPMCRegisterInfo` 関数を呼び出します。なおこの関数の第二引数には
関数の戻りアドレスが入るレジスタを指定しますfootnote:[内部で
`llvm::MCRegisterInfo::InitMCRegisterInfo` <<llvm_doxygen-InitMCRegisterInfo>>
を呼び出していることからわかります。]。
CAHPではx0を表す `CAHP::X0` を渡すことになります。
// FIXME: 要確認return addressをスタックに積むx86では `eip` をx86_64では `rip` を)返している。なぜかは良くわからない。
`CAHPMCSubtargetInfo` も同様に自動生成されます。
`createCAHPMCSubtargetInfoImpl` を呼び出します。この関数の第二引数には
`CAHP.td` で `ProcessorModel` として定義したCPUの名前を指定します。
`CAHPMCCodeEmitter` はアセンブリのエンコード作業を行います。
`MCTargetDesc/CAHPMCCodeEmitter.cpp` に記述します。
主要なエンコード処理はTableGenによって自動生成された
`getBinaryCodeForInstr` を `CAHPMCCodeEmitter::encodeInstruction`
から呼び出すことによって行われます。
この関数は `CAHPGenMCCodeEmitter.inc` というファイルに定義されるため、
これを `MCTargetDesc/CAHPMCCodeEmitter.cpp` 末尾で `#include` しておきます。
`CAHPAsmBackend` にはオブジェクトファイルを作成する際に必要な
fixupの操作や指定バイト数分の無効命令を書き出す処理などを記述します。
`MCTargetDesc/CAHPAsmBackend.cpp` に記述します。
fixupについては後ほど実装するためここではスタブにしておきます。
`CAHPELFObjectWriter` にはELFファイルの特にヘッダを作成する際に必要な情報を記載します。
このクラスは `LLVMInitializeCAHPTargetMC` ではなく
`CAHPAsmBackend` の `createObjectTargetWriter` メンバ関数として紐付けられます。
親クラス `MCELFObjectTargetWriter` のコンストラクタに、
CAHPマシンを表す `ELF::EM_CAHP` と、 `.rel` ではなく `.rela` を使用する旨を示す
`true` を渡しておきますfootnote:[CAHPマシンの仕様などはこの世に存在しないので、
これらは勝手に決めたものです。]。
// FIXME: .rel と .rela の説明をする。原則これは歴史的事情で決まっているものなので
// どっちでもいい、みたいな話がLLDのコメントだったかELFの仕様書だったかに
// 書いてあった気がする。覚えてない。
また `getRelocType` メンバ関数はどのような再配置を行うかを見繕うためのものですが、
ここではスタブにしておきます。
上記を実装してビルドします。一度使ってみましょう。
LLVMのアセンブラを単体で使う場合は `llvm-mc` というコマンドを使用します。
次のようにすると `foo.s` というアセンブリファイルをオブジェクトファイルに
変換できます。
$ bin/llvm-mc -arch=cahp -filetype=obj foo.s
bin/llvm-mc: error: this target does not support assembly parsing.
このようなエラーメッセージが出れば成功ですfootnote:[失敗した場合は
assertなどで異常終了し、スタックトレースなどが表示されます。]。
// FIXME: 要確認:「成功」のときもスタックトレース出た気もする。
続いてアセンブリをパーズする部分を開発します。
=== `CAHPAsmParser` を追加する
アセンブリのパーズは `CAHPAsmParser` が取り仕切っています。
=== `CAHPInstPrinter` を実装する
=== テストを書く
=== メモリ演算を追加する
=== 属性を指定する
=== ディスアセンブラを実装する
=== relocationとfixupに対応する
=== `%hi` と `%lo` に対応する
=== `li a0, foo` をエラーにする
=== llvm-objdump の調査
=== `hlt` 疑似命令を追加する
== コード生成部を作る
=== コンパイラのスケルトンを作成する
=== 基本的な演算に対応する
=== 定数の実体化に対応する
=== メモリ演算に対応する
=== relocationに対応する
=== 条件分岐に対応する
=== 関数呼び出しに対応する
=== 関数プロローグ・エピローグを実装する
=== frame pointer eliminationを実装する
=== `select` に対応する
=== `FrameIndex` をlowerする。
=== 大きなスタックフレームに対応する
=== `SETCC` に対応する
=== `ExternalSymbol` に対応する
=== jump tableを無効化する
=== インラインアセンブリに対応する
=== fastccに対応する
== Cコンパイラに仕立てる
=== LLDにCAHPバックエンドを追加する
=== ClangをCAHPに対応させる
=== `crt0.o` と `cahp.lds` の導入
=== `--nmagic` の有効化
=== libcの有効化
== まともなコードを生成する
=== 分岐解析に対応する
=== branch relaxationに対応する
=== 16bit命令を活用する
=== `jal` を活用する
=== 命令スケジューリングを設定する
=== 末尾再帰に対応する
== 落ち穂拾い
=== スタックを利用した引数渡し
=== `byval` の対応
=== 動的なスタック領域確保に対応する
=== emergency spillに対応する
=== 可変長引数関数に対応する
=== 単体の `sext/zext/trunc` に対応する
=== 乗算に対応する
=== 除算・剰余に対応する
=== `frameaddr/returnaddr` に対応する
=== `ROTL/ROTR/BSWAP/CTTZ/CTLZ/CTPOP` に対応する
=== 32bitのシフトに対応する
=== 間接ジャンプに対応する
=== `BlockAddress` のlowerに対応する
[bibliography]
== 参考文献
- [[[github_riscv-llvm_docs_01,1]]] https://github.com/lowRISC/riscv-llvm/blob/master/docs/01-intro-and-building-llvm.mkd
- [[[llvm_getting-started,2]]] https://llvm.org/docs/GettingStarted.html
- [[[clang_gettings-started,3]]] https://clang.llvm.org/get_started.html
- [[[asciidoctor_user-manual,4]]] https://asciidoctor.org/docs/user-manual/
- [[[riscv,5]]] https://riscv.org/
- [[[riscv_specifications,6]]] https://riscv.org/specifications/
- [[[fox-llvm,7]]] 『きつねさんでもわかるLLVM〜コンパイラを自作するためのガイドブック〜』柏木 餅子・風薬・矢上 栄一、株式会社インプレス、2013年
- [[[github_riscv-llvm_docs_02,8]]] https://github.com/lowRISC/riscv-llvm/blob/master/docs/02-starting-the-backend.mkd
- [[[github_riscv-llvm_patch_02,9]]] https://github.com/lowRISC/riscv-llvm/blob/master/0002-RISCV-Recognise-riscv32-and-riscv64-in-triple-parsin.patch
- [[[github_riscv-llvm,10]]] https://github.com/lowRISC/riscv-llvm
- [[[youtube_llvm-backend-development-by-example,11]]] https://www.youtube.com/watch?v=AFaIP-dF-RA
- [[[msyksphinz_try-riscv64-llvm-backend,12]]] http://msyksphinz.hatenablog.com/entry/2019/01/02/040000_1
- [[[github_riscv-llvm_patch_03,13]]] https://github.com/lowRISC/riscv-llvm/blob/master/0003-RISCV-Add-RISC-V-ELF-defines.patch
- [[[github_riscv-llvm_patch_04,14]]] https://github.com/lowRISC/riscv-llvm/blob/master/0004-RISCV-Add-stub-backend.patch
- [[[github_riscv-llvm_patch_06,15]]] https://github.com/lowRISC/riscv-llvm/blob/master/0006-RISCV-Add-bare-bones-RISC-V-MCTargetDesc.patch
- [[[github_riscv-llvm_patch_10,16]]] https://github.com/lowRISC/riscv-llvm/blob/master/0010-RISCV-Add-support-for-disassembly.patch
- [[[llvm-writing_backend-operand_mapping,17]]] https://llvm.org/docs/WritingAnLLVMBackend.html#instruction-operand-mapping
- [[[llvm-writing_backend,18]]] https://llvm.org/docs/WritingAnLLVMBackend.html
- [[[github_riscv-llvm_patch_07,19]]] https://github.com/lowRISC/riscv-llvm/blob/master/0007-RISCV-Add-basic-RISCVAsmParser.patch
- [[[github_riscv-llvm_patch_08,20]]] https://github.com/lowRISC/riscv-llvm/blob/master/0008-RISCV-Add-RISCVInstPrinter-and-basic-MC-assembler-te.patch
- [[[llvm-tablegen,21]]] https://llvm.org/docs/TableGen/index.html
- [[[github_riscv-llvm_patch_09,22]]] https://github.com/lowRISC/riscv-llvm/blob/master/0009-RISCV-Add-support-for-all-RV32I-instructions.patch
- [[[llvm_dev_ml-tablegen_definition_question,23]]] http://lists.llvm.org/pipermail/llvm-dev/2015-December/093310.html
- [[[llvm_doxygen-twine,24]]] https://llvm.org/doxygen/classllvm_1_1Twine.html
- [[[llvm-tablegen-langref,25]]] https://llvm.org/docs/TableGen/LangRef.html
- [[[github_riscv-llvm_docs_05,26]]] https://github.com/lowRISC/riscv-llvm/blob/master/docs/05-disassembly.mkd
- [[[github_riscv-llvm_patch_11,27]]] https://github.com/lowRISC/riscv-llvm/blob/master/0011-RISCV-Add-common-fixups-and-relocations.patch
- [[[github_riscv-llvm_docs_06,28]]] https://github.com/lowRISC/riscv-llvm/blob/master/docs/06-relocations-and-fixups.mkd
- [[[github_riscv-llvm_patch_13,29]]] https://github.com/lowRISC/riscv-llvm/blob/master/0013-RISCV-Initial-codegen-support-for-ALU-operations.patch
- [[[speakerdeck-llvm_backend_development,30]]] https://speakerdeck.com/asb/llvm-backend-development-by-example-risc-v
- [[[llvm-code_generator,31]]] https://llvm.org/docs/CodeGenerator.html
- [[[llvm-code_generator-target_independent_code_gen_alg,32]]] https://llvm.org/docs/CodeGenerator.html#target-independent-code-generation-algorithms
- [[[llvm-code_generator-selectiondag_instruction_selection,33]]] https://llvm.org/docs/CodeGenerator.html#selectiondag-instruction-selection-process
- [[[github_riscv-llvm_patch_15,34]]] https://github.com/lowRISC/riscv-llvm/blob/master/0015-RISCV-Codegen-support-for-memory-operations.patch
- [[[cpu0,35]]] https://jonathan2251.github.io/lbd/
- [[[elvm-llvm_backend,36]]] https://github.com/shinh/llvm/tree/elvm
- [[[elvm-slide,37]]] http://shinh.skr.jp/slide/llel/000.html
- [[[github_riscv-llvm_patch_16,38]]] https://github.com/lowRISC/riscv-llvm/blob/master/0016-RISCV-Codegen-support-for-memory-operations-on-globa.patch
- [[[github_riscv-llvm_patch_17,39]]] https://github.com/lowRISC/riscv-llvm/blob/master/0017-RISCV-Codegen-for-conditional-branches.patch
- [[[todai_llvm_backend,40]]] https://github.com/cpu-experiment-2018-2/llvm/tree/master/lib/Target/ELMO
- [[[todai_llvm_backend-article,41]]] http://uenoku.hatenablog.com/entry/2018/12/25/044244
- [[[github_riscv-llvm_patch_18,42]]] https://github.com/lowRISC/riscv-llvm/blob/master/0018-RISCV-Support-for-function-calls.patch
- [[[llvm-langref,43]]] http://llvm.org/docs/LangRef.html
- [[[fpga_develop_diary,44]]] http://msyksphinz.hatenablog.com/
- [[[llvm-anton_korobeynikov_2012,45]]] https://llvm.org/devmtg/2012-04-12/Slides/Workshops/Anton_Korobeynikov.pdf
- [[[llvm-welcome_to_the_back_end_2017,46]]] https://www.youtube.com/watch?v=objxlZg01D0
- [[[ean10-howto-llvmas,47]]] https://www.embecosm.com/appnotes/ean10/ean10-howto-llvmas-1.0.html
- [[[lowrisc-devmtg18,48]]] https://www.lowrisc.org/llvm/devmtg18/
- [[[LLVMBackend_2015_03_26_v2,49]]] http://www.inf.ed.ac.uk/teaching/courses/ct/other/LLVMBackend-2015-03-26_v2.pdf
- [[[rui-compilerbook,50]]] https://www.sigbus.info/compilerbook
- [[[krister-writing_gcc_backend,51]]] https://kristerw.blogspot.com/2017/08/writing-gcc-backend_4.html
- [[[llvm-ml-129089,52]]] http://lists.llvm.org/pipermail/llvm-dev/2019-January/129089.html
- [[[llvm-langref-datalayout,53]]] https://llvm.org/docs/LangRef.html#langref-datalayout
- [[[github-frasercrmck_llvm_leg,54]]] https://github.com/frasercrmck/llvm-leg/tree/master/lib/Target/LEG
- [[[llvm_doxygen-InitMCRegisterInfo,55]]] https://llvm.org/doxygen/classllvm_1_1MCRegisterInfo.html#a989859615fcb74989b4f978c4d227a03
- [[[llvm-programmers_manual,56]]] http://llvm.org/docs/ProgrammersManual.html
- [[[llvm-writing_backend-calling_conventions,57]]] https://llvm.org/docs/WritingAnLLVMBackend.html#calling-conventions
- [[[riscv-calling,58]]] https://riscv.org/wp-content/uploads/2015/01/riscv-calling.pdf
- [[[llvm_dev_ml-how_to_debug_instruction_selection,59]]] http://lists.llvm.org/pipermail/llvm-dev/2017-August/116501.html
- [[[fpga_develop_diary-20190612040000,60]]] http://msyksphinz.hatenablog.com/entry/2019/06/12/040000
- [[[llvm_dev_ml-br_cc_questions,61]]] http://lists.llvm.org/pipermail/llvm-dev/2014-August/075303.html
- [[[llvm_dev_ml-multiple_result_instrs,62]]] https://groups.google.com/forum/#!topic/llvm-dev/8kPOj-_lbGk
- [[[stackoverflow-frame_lowering,63]]] https://stackoverflow.com/questions/32872946/what-is-stack-frame-lowering-in-llvm
- [[[llvm_dev_ml-selecting_frame_index,64]]] https://groups.google.com/d/msg/llvm-dev/QXwtqgau-jA/PwnHDF0gG_oJ
- [[[fpga_develop_diary-llvm,65]]] https://github.com/msyksphinz/llvm/tree/myriscvx/impl90/lib/Target/MYRISCVX
- [[[llvm-github_cd44ae,66]]] https://github.com/llvm/llvm-project/commit/cd44aee3da22f9a618f2e63c226bebf615fa8cf8
- [[[llvm_phabricator-d43752,67]]] https://reviews.llvm.org/D43752
- [[[llvm-compilerwriterinfo,68]]] https://llvm.org/docs/CompilerWriterInfo.html
- [[[wikipedia-The_Gleaners,69]]] https://en.wikipedia.org/wiki/The_Gleaners
- [[[github_riscv-llvm_patch_20,70]]] https://github.com/lowRISC/riscv-llvm/blob/master/0020-RISCV-Support-and-tests-for-a-variety-of-additional-.patch
- [[[llvm_phabricator-d47422,71]]] https://reviews.llvm.org/D47422
- [[[llvm-extendingllvm,72]]] https://llvm.org/docs/ExtendingLLVM.html
- [[[llvm_dev_ml-001264,73]]] http://lists.llvm.org/pipermail/llvm-dev/2004-June/001264.html
- [[[llvm_phabricator-d42958,74]]] https://reviews.llvm.org/D42958
- [[[compiler_rt,75]]] https://compiler-rt.llvm.org/
- [[[github-riscv_compiler_rt,76]]] https://github.com/andestech/riscv-compiler-rt
- [[[github_riscv-llvm_patch_27,77]]] https://github.com/lowRISC/riscv-llvm/blob/master/0027-RISCV-Support-stack-frames-and-offsets-up-to-32-bits.patch
- [[[llvm_phabricator-d44885,78]]] https://reviews.llvm.org/D44885
- [[[llvm_phabricator-d45859,79]]] https://reviews.llvm.org/D45859
- [[[llvm-langref-poison_value,80]]] http://llvm.org/docs/LangRef.html#poisonvalues
- [[[github-emscripten-issues-34,81]]] https://github.com/emscripten-core/emscripten/issues/34
- [[[switch_lowering_in_llvm,82]]] http://fileadmin.cs.lth.se/cs/education/edan75/part2.pdf
- [[[github-avr_llvm-issues-88,83]]] https://github.com/avr-llvm/llvm/issues/88
- [[[asciidoctor-quickref,84]]] https://asciidoctor.org/docs/asciidoc-syntax-quick-reference/
- [[[llvm_phabricator-d56351,85]]] https://reviews.llvm.org/D56351
- [[[hatenablog-rhysd-230119,86]]] https://rhysd.hatenablog.com/entry/2017/03/13/230119
- [[[llvm_dev_ml-115805,87]]] http://lists.llvm.org/pipermail/llvm-dev/2017-July/115805.html
- [[[github_riscv-llvm_patch_29,88]]] https://github.com/lowRISC/riscv-llvm/blob/master/0029-RISCV-Add-support-for-llvm.-frameaddress-returnaddre.patch
- [[[github-riscv_llvm-clang,89]]] https://github.com/lowRISC/riscv-llvm/tree/master/clang
- [[[github-elvm_clang,90]]] https://github.com/shinh/clang/tree/elvm
- [[[github_riscv-llvm_patch_22,91]]] https://github.com/lowRISC/riscv-llvm/blob/master/0022-RISCV-Support-lowering-FrameIndex.patch
- [[[llvm_dev_ml-087879,92]]] http://lists.llvm.org/pipermail/llvm-dev/2015-July/087879.html
- [[[stackoverflow-27467293,93]]] https://stackoverflow.com/questions/27467293/how-to-force-clang-use-llvm-assembler-instead-of-system
- [[[github-riscv_llvm-clang-03,94]]] https://github.com/lowRISC/riscv-llvm/blob/master/clang/0003-RISCV-Implement-clang-driver-for-the-baremetal-RISCV.patch
- [[[github_riscv-llvm_patch_25,95]]] https://github.com/lowRISC/riscv-llvm/blob/master/0025-RISCV-Add-custom-CC_RISCV-calling-convention-and-imp.patch
- [[[llvm_dev_ml-106187,96]]] http://lists.llvm.org/pipermail/llvm-dev/2016-October/106187.html
- [[[llvm_phabricator-d39322,97]]] https://reviews.llvm.org/D39322
- [[[cpu0-lld,98]]] http://jonathan2251.github.io/lbt/lld.html
- [[[youtube-how_to_add_a_new_target_to_lld,99]]] https://www.youtube.com/watch?v=FIXaeRU31Ww
- [[[llvm-smith_newlldtargetpdf,100]]] https://llvm.org/devmtg/2016-09/slides/Smith-NewLLDTarget.pdf
- [[[llvm-lld,101]]] https://lld.llvm.org/index.html
- [[[note-n9948f0cc3ed3,102]]] https://note.mu/ruiu/n/n9948f0cc3ed3
- [[[lanai-isa,103]]] https://docs.google.com/document/d/1jwAc-Rbw1Mn7Dbn2oEB3-0FQNOwqNPslZa-NDy8wGRo/pub
- [[[github-blog_os-issues-370,104]]] https://github.com/phil-opp/blog_os/issues/370
- [[[llvm_phabricator-d61688,105]]] https://reviews.llvm.org/D61688
- [[[man-xtensa_linux_gnu_ld,106]]] https://linux.die.net/man/1/xtensa-linux-gnu-ld
- [[[man-elf,107]]] https://linuxjm.osdn.jp/html/LDP_man-pages/man5/elf.5.html
- [[[llvm_phabricator-d45385,108]]] https://reviews.llvm.org/D45385
- [[[llvm_phabricator-d47882,109]]] https://reviews.llvm.org/D47882
- [[[llvm_dev_ml-128257,110]]] https://lists.llvm.org/pipermail/llvm-dev/2018-December/128257.html
- [[[github_riscv-llvm_patch_31,111]]] https://github.com/lowRISC/riscv-llvm/blob/master/0031-RISCV-Implement-support-for-the-BranchRelaxation-pas.patch
- [[[github_riscv-llvm_patch_30,112]]] https://github.com/lowRISC/riscv-llvm/blob/master/0030-RISCV-Implement-branch-analysis.patch
- [[[stackoverflow-5789806,113]]] https://stackoverflow.com/questions/5789806/meaning-of-and-in-c
- [[[compiler_study_report,114]]] https://proc-cpuinfo.fixstars.com/2018/11/compiler_study_report/
- [[[github-llvm-bcb36be8e3f5dced36710ba1a2e2206071ccc7ba,115]]] https://github.com/llvm/llvm-project/commit/bcb36be8e3f5dced36710ba1a2e2206071ccc7ba
- [[[llvm_dev_ml-059799,116]]] http://lists.llvm.org/pipermail/llvm-dev/2013-February/059799.html
- [[[tricore-llvm-slides,117]]] https://reup.dmcs.pl/wiki/images/7/7a/Tricore-llvm-slides.pdf
- [[[tricore-llvm,118]]] https://opus4.kobv.de/opus4-fau/files/1108/tricore_llvm.pdf
- [[[llvm_dev_ml-111697,119]]] http://lists.llvm.org/pipermail/llvm-dev/2017-April/111697.html
- [[[takayuki-no09,120]]] http://www.ertl.jp/~takayuki/readings/c/no09.html
- [[[hwenginner-linker,121]]] https://hwengineer.github.io/linker/
- [[[koikikukan-000300,122]]] http://www.koikikukan.com/archives/2017/04/05-000300.php
- [[[stackoverflow-57735654_34997577,123]]] https://stackoverflow.com/questions/34997577/linker-script-allocation-of-bss-section#comment57735654_34997577
- [[[redhat-ld_simple_example,124]]] https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/4/html/Using_ld_the_GNU_Linker/simple-example.html
- [[[llvm_phabricator-d45395,125]]] https://reviews.llvm.org/D45395
- [[[llvm_phabricator-d45395-398662,126]]] https://reviews.llvm.org/D45395#inline-398662
- [[[llvm-langref-inline_asm,127]]] http://llvm.org/docs/LangRef.html#inline-assembler-expressions
- [[[hazymoon-gcc_inline_asm,128]]] http://caspar.hazymoon.jp/OpenBSD/annex/gcc_inline_asm.html
- [[[github_riscv-llvm_patch_28,129]]] https://github.com/lowRISC/riscv-llvm/blob/master/0028-RISCV-Add-basic-support-for-inline-asm-constraints.patch
- [[[llvm-langref-inline_asm-asm_template_argument_modifier,130]]] http://llvm.org/docs/LangRef.html#asm-template-argument-modifiers
- [[[github-llvm-0715d35ed5ac2312951976bee2a0d2587f98f39f,131]]] https://github.com/llvm/llvm-project/commit/0715d35ed5ac2312951976bee2a0d2587f98f39f
- [[[github_riscv-llvm_patch_32,132]]] https://github.com/lowRISC/riscv-llvm/blob/master/0032-RISCV-Reserve-an-emergency-spill-slot-for-the-regist.patch
- [[[github_riscv-llvm_patch_26,133]]] https://github.com/lowRISC/riscv-llvm/blob/master/0026-RISCV-Support-for-varargs.patch
- [[[github-fracture-wiki-how-dagisel-works,134]]] https://github.com/draperlaboratory/fracture/wiki/How-TableGen%27s-DAGISel-Backend-Works
- [[[welcome_to_the_back_end-slides,135]]] http://llvm.org/devmtg/2017-10/slides/Braun-Welcome%20to%20the%20Back%20End.pdf
- [[[life_of_an_instruction,136]]] https://eli.thegreenplace.net/2012/11/24/life-of-an-instruction-in-llvm/
- [[[shinh-blog-010637,137]]] http://shinh.hatenablog.com/entry/2014/10/03/010637
- [[[llvm_backend_intro,138]]] https://www.slideshare.net/AkiraMaruoka/llvm-backend
- [[[amazon-llvm_cookbook-customer_review,139]]] https://www.amazon.co.jp/dp/178528598X#customer_review-R28L2NAL8T9M2H
- [[[llvm_dev_ml-117139,140]]] https://lists.llvm.org/pipermail/llvm-dev/2017-September/117139.html
- [[[github_riscv-llvm_patch_85,141]]] https://github.com/lowRISC/riscv-llvm/blob/master/0085-RISCV-Set-AllowRegisterRenaming-1.patch
- [[[llvm_dev_ml-135337,142]]] https://lists.llvm.org/pipermail/llvm-dev/2019-September/135337.html
- [[[wikipedia-weak_symbol,143]]] https://en.wikipedia.org/wiki/Weak_symbol
- [[[wikipedia-remat,144]]] https://en.wikipedia.org/wiki/Rematerialization
- [[[llvm_phabricator-d46182,145]]] https://reviews.llvm.org/D46182
- [[[nakata-compiler,146]]] 『コンパイラの構成と最適化第2版中田育男、朝倉書店、2009
- [[[fpga_develop_diary-to_llvm9,147]]] http://msyksphinz.hatenablog.com/entry/2019/08/17/040000
- [[[llvm_phabricator-d60488,148]]] https://reviews.llvm.org/D60488
- [[[llvm_phabricator-rl364191,149]]] https://reviews.llvm.org/rL364191
- [[[llvm_phabricator-d64121,150]]] https://reviews.llvm.org/D64121
- [[[llvm-codingstandards,151]]] https://llvm.org/docs/CodingStandards.html
- [[[llvm_dev_ml-134921,152]]] https://lists.llvm.org/pipermail/llvm-dev/2019-September/134921.html
- [[[llvm_phabricator-d43256,153]]] https://reviews.llvm.org/D43256
- [[[llvm_dev_ml-114675,154]]] http://lists.llvm.org/pipermail/llvm-dev/2017-June/114675.html
- [[[llvm_phabricator-d42780,155]]] https://reviews.llvm.org/D42780
- [[[llvm_phabricator-d51732,156]]] https://reviews.llvm.org/D51732
- [[[llvm_devmtg-schedmachinemodel,157]]] http://llvm.org/devmtg/2014-10/Slides/Estes-MISchedulerTutorial.pdf
- [[[llvm_dev_ml-098535,158]]] https://lists.llvm.org/pipermail/llvm-dev/2016-April/098535.html
- [[[llvm_devmtg-writinggreatsched,159]]] https://www.youtube.com/watch?v=brpomKUynEA
- [[[anandtech-11441,160]]] https://www.anandtech.com/show/11441/dynamiq-and-arms-new-cpus-cortex-a75-a55/4
- [[[llvm_devmtg-larintrick,161]]] https://llvm.org/devmtg/2012-11/Larin-Trick-Scheduling.pdf
- [[[llvm-schedinorder,162]]] https://llvm.org/devmtg/2016-09/slides/Absar-SchedulingInOrder.pdf