From 629606e592d42fe867c69a6022d564630250b5b1 Mon Sep 17 00:00:00 2001 From: "Ushitora Anqou (via Travis CI)" Date: Wed, 25 Mar 2020 08:32:25 +0000 Subject: [PATCH] Deploy ushitora-anqou/write-your-llvm-backend to github.com/ushitora-anqou/write-your-llvm-backend.git:gh-pages --- index.html | 1786 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1786 insertions(+) create mode 100644 index.html diff --git a/index.html b/index.html new file mode 100644 index 0000000..edfa2cd --- /dev/null +++ b/index.html @@ -0,0 +1,1786 @@ + + + + + + + + +自作ISAのためのLLVMバックエンドを書く薄い本 + + + + + + +
+
+

FIXME

+
+
+

文中のFIXME他直すべきものをここにリストにする。

+
+
+
    +
  • +

    だ・である調をです・ます調に変える。

    +
  • +
+
+
+
+
+

この文書について

+
+
+

この文書はAsciiDocを用いて執筆されています。

+
+
+

この文書はGitによって管理され、 +GitHubリポジトリにて +公開されています

+
+
+

この作品は、クリエイティブ・コモンズの 表示 4.0 国際 ライセンスで提供されています。ライセンスの写しをご覧になるには、 http://creativecommons.org/licenses/by/4.0/ をご覧頂くか、Creative Commons, PO Box 1866, Mountain View, CA 94042, USA までお手紙をお送りください。

+
+
+

本文書の内容は筆者が独自に調査したものです。 +疑う余地なく誤りが含まれます。誤りに気づかれた方はGitHubリポジトリなどを通じて +ご連絡ください。

+
+
+
+
+

LLVMバックエンド概略

+
+
+

本書ではRISC-V風味の独自ISAを例にLLVMバックエンドを開発します。

+
+
+

使用するLLVMのバージョンはv9.0.0です。

+
+
+
+
+

ところで

+
+
+

一度もコンパイラを書いたことがない人は、この文書を読む前に +『低レイヤを知りたい人のためのCコンパイラ作成入門』[50]などで一度 +フルスクラッチからコンパイラを書くことをおすすめします。

+
+
+

また[51]などを参考に、 +LLVMではなくGCCにバックエンドを追加することも検討してみてはいかがでしょうか。

+
+
+
+
+

参考にすべき文献

+
+
+

LLVMバックエンドを開発する際に参考にできる書籍やWebサイトを以下に一覧します。 +なおこの文書では、RISC-Vバックエンド及びそれに関する技術資料を大いに参考しています。

+
+
+

Webページ

+
+
    +
  • +

    Writing an LLVM Backend[18]

    +
    +
      +
    • +

      分かりにくく読みにくい。正直あんまり見ていないが、たまに眺めると有益な情報を見つけたりもする。

      +
    • +
    +
    +
  • +
  • +

    The LLVM Target-Independent Code Generator[31]

    +
    +
      +
    • +

      [18]よりもよほど参考になる。LLVMバックエンドがどのようにLLVM IRをアセンブリに落とすかが明記されている。必読。

      +
    • +
    +
    +
  • +
  • +

    TableGenのLLVMのドキュメント[21]

    +
    +
      +
    • +

      情報量が少ない。これを読むよりも各種バックエンドのTableGenファイルを読むほうが良い。

      +
    • +
    +
    +
  • +
  • +

    LLVM Language Reference Manual[43]

    +
    +
      +
    • +

      LLVM IRについての言語リファレンス。LLVM IRの仕様などを参照できる。必要に応じて読む。

      +
    • +
    +
    +
  • +
  • +

    Architecture & Platform Information for Compiler Writers[68]

    +
    +
      +
    • +

      LLVMで公式に実装されているバックエンドに関するISAの情報が集約されている。Lanaiの言語仕様へのリンクが貴重。

      +
    • +
    +
    +
  • +
  • +

    RISC-V support for LLVM projects[10]

    +
    +
      +
    • +

      どちゃくそに参考になる。以下の開発はこれに基づいて行う。

      +
    • +
    • +

      LLVMにRISC-Vサポートを追加するパッチ群。バックエンドを開発するためのチュートリアルも兼ねているらしく docs/ 及びそれと対応したpatchが参考になる。

      +
    • +
    • +

      またこれについて、開発者が2018 LLVM Developers' Meetingで登壇したときの動画は[11]より閲覧できる。スライドは[30]より閲覧できる。

      +
    • +
    • +

      そのときのCoding Labは[48]より閲覧できる。

      +
    • +
    +
    +
  • +
  • +

    Create an LLVM Backend for the Cpu0 Architecture[35]

    +
    +
      +
    • +

      Cpu0という独自アーキテクチャのLLVMバックエンドを作成するチュートリアル。多少古いが、内容が網羅的で参考になる。英語が怪しい。

      +
    • +
    +
    +
  • +
  • +

    FPGA開発日記[44]

    +
    +
      +
    • +

      Cpu0の資料[35]をもとに1からRISC-Vバックエンドを作成する過程がブログエントリとして公開されている。GitHubに実装も公開されている[65]

      +
    • +
    +
    +
  • +
  • +

    ELVMバックエンド[36]

    +
    +
      +
    • +

      限られた命令でLLVM IRの機能を達成する例として貴重。でも意外とISAはリッチだったりする。

      +
    • +
    • +

      作成者のスライドも参考になる[37]

      +
    • +
    +
    +
  • +
  • +

    2018年度東大CPU実験で開発されたLLVM Backend[40]

    +
    +
      +
    • +

      これについて書かれたAdCのエントリもある[41]

      +
    • +
    +
    +
  • +
  • +

    Tutorial: Building a backend in 24 hours[45]

    +
    +
      +
    • +

      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"[46]

    +
    +
      +
    • +

      スライドも公開されている[135]

      +
    • +
    • +

      命令選択が終わったあとの中間表現であるLLVM MIR +( MachineFunctionMachineInstr など)や、それに対する操作の解説。 +RegStateやframe index・register scavengerなどの説明が貴重。

      +
    • +
    +
    +
  • +
  • +

    Howto: Implementing LLVM Integrated Assembler[47]

    +
    +
      +
    • +

      LLVM上でアセンブラを書くためのチュートリアル。アセンブラ単体に焦点を絞ったものは珍しい。

      +
    • +
    +
    +
  • +
  • +

    Building an LLVM Backend[49]

    +
    +
      +
    • +

      対応するレポジトリが[54]にある。

      +
    • +
    +
    +
  • +
  • +

    [LLVMdev] backend documentation[116]

    +
    +
      +
    • +

      llvm-devメーリングリストのバックエンドのよいドキュメントは無いかというスレッド。Cpu0とTriCoreが挙げられているが、深くまで記述したものは無いという回答。

      +
    • +
    +
    +
  • +
  • +

    TriCore Backend[118]

    +
    +
      +
    • +

      TriCoreというアーキテクチャ用のバックエンドを書いたという論文。スライドもある[117]。ソースコードもGitHub上に上がっているが、どれが公式かわからない[1]

      +
    • +
    +
    +
  • +
  • +

    Life of an instruction in LLVM[136]

    +
    +
      +
    • +

      Cコードからassemblyまでの流れを概観。

      +
    • +
    +
    +
  • +
  • +

    LLVM Backendの紹介[138]

    +
    +
      +
    • +

      「コンパイラ勉強会」[2]。]での、LLVMバックエンドの大きな流れ(特に命令選択)について概観した日本語スライド。

      +
    • +
    +
    +
  • +
+
+
+
+

書籍

+
+
    +
  • +

    『きつねさんでもわかるLLVM〜コンパイラを自作するためのガイドブック〜』[7]

    +
    +
      +
    • +

      数少ない日本語資料。Passやバックエンドの各クラスについて説明している。[31]と合わせて大まかな流れを掴むのに良い。

      +
    • +
    +
    +
  • +
+
+
+

なおLLVMについてGoogleで検索していると"LLVM Cookbook"なる謎の書籍(の電子コピー)が +見つかるが、内容はLLVM公式文書のパクリのようだ[139]

+
+
+
+

バックエンド

+
+
    +
  • +

    RISC-V[5]

    +
    +
      +
    • +

      パッチ群が開発ドキュメントとともに公開されている[10]。以降の開発はこれをベースに行う。

      +
    • +
    +
    +
  • +
  • +

    Lanai[103]

    +
    +
      +
    • +

      Googleが開発した32bit RISCの謎アーキテクチャ。全く実用されていないが、バックエンドが単純に設計されておりコメントも豊富のためかなり参考になる[3][4] +にて指摘されているように、商業的に成功しなかったアーキテクチャほどコードが単純で分かりやすい。]

      +
    • +
    +
    +
  • +
  • +

    Sparc

    +
    +
      +
    • +

      [18]でも説明に使われており、コメントが豊富。

      +
    • +
    +
    +
  • +
  • +

    x86

    +
    +
      +
    • +

      みんな大好きx86。貴重なCISCの資料であり、かつ2オペランド方式を採用する場合に実装例を与えてくれる。あと EFLAGS の取り回しなども参考になるが、全体的にコードは読みにくい。ただLLVMの命名規則には従うため、他のバックエンドからある程度推論をして読むのが良い。

      +
    • +
    +
    +
  • +
+
+
+
+
+
+

ISAの仕様を決める

+
+
+

本書で使用するISAであるCAHPv3について説明します。

+
+
+

cahpv3.pdfを参考のこと。

+
+
+
+
+

スケルトンバックエンドを追加する

+
+
+

正常にLLVMのビルドを行うために、何の機能も無いバックエンド(スケルトンバックエンド)を +LLVMに追加します。

+
+
+
+
+

LLVMをビルドする

+
+
+

LLVMは巨大なプロジェクトで、ビルドするだけでも一苦労です。 +以下では継続的な開発のために、高速にLLVMをデバッグビルドする手法を紹介します。

+
+
+

ビルドの際には以下のソフトウェアが必要になります。

+
+
+
    +
  • +

    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を用いて行います。 +大量のオプションはビルドを早くするためのものです[96]

+
+
+
+
$ 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 .
+
+
+
+

ビルドが終了すると 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
+
+
+
+ + + + + +
+ + +
+

ここでは開発用にデバッグビルドを行いました。 +一方で、他人に配布する場合などはリリースビルドを行います。 +その際は次のようにCMakeのオプションを指定します。

+
+
+
+
$ 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のMCLayerを実装し、アセンブリからオブジェクトファイルへの変換を可能にします。

+
+
+

簡易的なアセンブラを実装する

+ +
+
+

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.ocahp.lds の導入

+ +
+
+

--nmagic の有効化

+ +
+
+

libcの有効化

+ +
+
+
+
+

まともなコードを生成する

+
+
+

分岐解析に対応する

+ +
+
+

branch relaxationに対応する

+ +
+
+

16bit命令を活用する

+ +
+
+

jal を活用する

+ +
+
+

命令スケジューリングを設定する

+ +
+
+

末尾再帰に対応する

+ +
+
+
+
+

落ち穂拾い

+
+
+

スタックを利用した引数渡し

+ +
+
+

byval の対応

+ +
+
+

動的なスタック領域確保に対応する

+ +
+
+

emergency spillに対応する

+ +
+
+

可変長引数関数に対応する

+ +
+
+

単体の sext/zext/trunc に対応する

+ +
+
+

乗算に対応する

+ +
+
+

除算・剰余に対応する

+ +
+
+

frameaddr/returnaddr に対応する

+ +
+
+

ROTL/ROTR/BSWAP/CTTZ/CTLZ/CTPOP に対応する

+ +
+
+

32bitのシフトに対応する

+ +
+
+

間接ジャンプに対応する

+ +
+
+

BlockAddress のlowerに対応する

+ +
+
+
+
+

参考文献

+
+
+ +
+
+
+
+
+
+
+1. 論文とスライドも怪しいものだが、著者が一致しているので多分正しいだろう。 +
+
+2. これとは別の発表で「コンパイラ開発してない人生はFAKE」という名言が飛び出した勉強会[114 +
+
+3. LLVMバックエンドの開発を円滑にするためのアーキテクチャなのではと思うほどに分かりやすい。 +
+
+4. 後のSparcについて[116 +
+
+ + + \ No newline at end of file