uint256_t
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Compiler optimizations # もくじ - コンパイラ最適化とは何か - コンパイラ最適化の代表例(概略) - これさえ実装すれば良い:8つの最適化 - コンパイラ最適化に適した、プログラムの形式 - SSA (Static Single Assignment) form - なぜ SSA はコンパイラ最適化に適しているか - SSAが実世界で使われている例: LLVM IR - SSAが実世界で使われている例: Cranelift IR - コンパイラ最適化の具体的な実装方法 - 普通のプログラム→SSA 変換 - 8つの最適化 ... # コンパイラ最適化とは何か コンパイラ最適化とはなんでしょうか。私のよく読む本([コンパイラの構成と最適化](https://www.asakura.co.jp/detail.php?book_code=12177), p.243)では以下のように定義されています。(以降、この本で「目的プログラムの最適化」と呼んでいるものを、この文章では「コンパイラ最適化」と呼びます。) > 目的プログラム(目的コードとも言う)の最適化(optimization)とは、効率のよい目的プログラムとすることである。 また、以下のように続きます。 > 一般には最もよい目的コードを作り出すことは不可能であり、「よりよい」コードとする努力をするだけである。 > 「適化」といったほうがよいかもしれないが、昔からコンパイラに関しては「最適化」という言葉が使われているので、ここでもそれを使うことにする。 おそらく、この定義が一般的な認識と大きくずれていることはないと思います。 要するに、コンパイラがプログラムをなんらかの方法で変換し、その結果、プログラムは(なんらかの指標において)より効率の良いものとなるのです。 (上の引用で述べられている通り、「最も良い」プログラムに変換することはできません。もしそのようなことが可能ならば、[停止性問題](https://ja.wikipedia.org/wiki/%E5%81%9C%E6%AD%A2%E6%80%A7%E5%95%8F%E9%A1%8C)を解いてしまうことになるからです。) この文章では、コンパイラ最適化について、理論と実装の両方について説明を試みます。誤字や特に知りたい内容などがあれば教えてください。 # コンパイラ最適化の代表例 世の中には非常に多くの最適化手法が存在しています。もちろん、すべてではありませんが、それらは実際にコンパイラに実装されているわけで、例えば [LLVM](https://ja.wikipedia.org/wiki/LLVM) には約100個の最適化手法が実装されています(Analysis + Transform passes の数, ターゲット依存のものも数えればもっと多いでしょう, ref. https://llvm.org/docs/Passes.html )。 様々な最適化を適用すれば、その分より良いプログラムが生成されやすくなるでしょう。(実際は、最適化手法を適用する順番でプログラムが変わったりするので一概には言えないのですが...) しかし、むやみにいろいろな最適化手法を実装してもあまり効率的ではありません。 そのため、ここでは**これさえ実装すれば十分な性能が出せるだろう**と言える8つの最適化に注目します。これ以外の最適化も後々紹介する予定です。(実際は、ひとつの最適化を実装するために、また他の手法を知らないといけない、ということがよく起きますからね。) なお、ここで紹介する最適化は[こちらのスライド (p.19)](http://venge.net/graydon/talks/CompilerTalk-2019.pdf)で紹介されています。参考として、[最適化手法のカタログ](https://www.clear.rice.edu/comp512/Lectures/Papers/1971-allen-catalog.pdf)も目を通すと良いでしょう。 さて、さっそくですが、以下がその最適化の一覧です。(私が適当に並び替えたので、スライドでの並び順とは異なります。下のほうがより実装が難しいかなぁと思いますが結構適当です。) - Constant Fold - DCE - Peephole - Inline - Unroll - CSE - Code Motion - Vectorize 名前を並べられてもよくわからないと思うので、一つづつ内容を確認していきましょう。 ## Constant Fold これは耳にしたことのある方も多いのではないでしょうか。日本語だと[定数畳み込み](https://ja.wikipedia.org/wiki/%E5%AE%9A%E6%95%B0%E7%95%B3%E3%81%BF%E8%BE%BC%E3%81%BF)と呼ばれている最適化です。 内容はとてもシンプルで、コンパイル時に計算できる部分は計算しておこうというものです。 具体的には以下のような変形を行います。 ```py # Constant Fold 前 x = 1 * 60 * 60 * 24 # Constant Fold 後 x = 86400 ``` また、コンパイル時に処理できれば良いので、例えば文字列同士の演算にも適用できます。(C言語だとあまり関係ないですが。) ```py # Constant Fold 前 s = "hello " + "world" # Constant Fold 後 s = "hello world" ``` ただ、浮動小数点数を畳み込んでも良いのかは言語仕様によります。コンパイル時と実行時で丸めモードが異なったり、演算の順番によって結果が変わってくる(結合法則が成り立たない)ことがあるからです。 実際に実装するときは、とりあえず整数値の畳み込みを実装すれば良いでしょう。 参考: [LLVMでの実装](https://github.com/llvm/llvm-project/blob/main/llvm/lib/IR/ConstantFold.cpp) ## 余談: Constant Propagation と Sparse Conditional Constant Propagation [定数伝播 (Constant Propagation)](https://ja.wikipedia.org/wiki/%E5%AE%9A%E6%95%B0%E7%95%B3%E3%81%BF%E8%BE%BC%E3%81%BF#%E5%AE%9A%E6%95%B0%E4%BC%9D%E6%92%AD) や [疎な条件分岐を考慮した定数伝播 (Sparse Conditional Constant Propagation, 長いので以下 SCCP)](https://ja.wikipedia.org/wiki/%E7%96%8E%E3%81%AA%E6%9D%A1%E4%BB%B6%E5%88%86%E5%B2%90%E3%82%92%E8%80%83%E6%85%AE%E3%81%97%E3%81%9F%E5%AE%9A%E6%95%B0%E4%BC%9D%E6%92%AD) を用いると、より多くのコードを定数へと畳み込むことができます。 定数伝播とは、(変数などの持つ)値が(ある範囲では)変化しないことを利用して、より多くのコードを定数畳み込みの対象とするものです。 例えば以下のような変形を行います。 ```py # Constant Propagation 前 x = 42 y = x + 1 # x が変数だから、Constant Fold できない... # Constant Propagation 後 x = 42 y = 42 + 1 # y への代入時には、x の値は 42 から変化していない。だから x を 42 で置き換えられる。 # Constant Fold できるようになった! ``` 定数伝播では、変数(上の例だと `x`)の値がどう変化しているか(変化していないか)が重要になってきます。このような情報を解析するためには、データフロー解析([Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%87%E3%83%BC%E3%82%BF%E3%83%95%E3%83%AD%E3%83%BC%E8%A7%A3%E6%9E%90), [うまくまとまっているQiitaの記事](https://qiita.com/fukkun/items/39c40abb1e9e5e53b7d7))の実装が必要です。こちらについても後述予定です。 また、SCCP はプログラム中の条件分岐に注目することで、より多くのコードを定数畳み込みの対象とします。 例えば以下のような変形を行います。 ```py # SCCP 前 x = 42 y = 0 if (x == 42) { y = 1 } else { y = 2 } z = y + 1 # SCCP 後 x = 42 y = 0 # この時点で x == 42 だから、if では y = 1 が実行される。 y = 1 # 下の if はごっそり削除 # if (x == 42) { # y = 1 # } else { # y = 2 # } z = 1 + 1 # だから y を 1 で置き換えられる。 # Constant Fold できるようになった! ``` ## DCE (Dead Code Elimination) DCE (Dead Code Elimination, デッドコード削除) とは、冗長なコードや実行されることのないコードを削除する最適化です。ここでもデータフロー解析が必要になります。 例えば以下のような変換を行います。 ```py # DCE 前 a = 1 b = 2 c = 3 return a + b # DCE 後 a = 1 b = 2 # c = 3 # 削除 return a + b ``` ```py # DCE 前 a = 1 b = 2 c = b + 1 return a # DCE 後 a = 1 # c は使われないから削除 # c で参照されていた b も削除 # ↑ バックトラックが必要な時もある (→ SSAを導入すると楽になる) # b = 2 # c = b + 1 return a ``` DCE 前後に Constant Fold (SCCP) を行うと、より多くのコードを削除できます。 ```py # SCCP 前 a = 1 if (a == 1) a = 2; else a = 3; return a # SCCP 後 (DCE 前) a = 1 a = 2 return a # DCE 後 # a = 1 # 下の a = 2 が実行されるまでに、a の値は参照されていない # 冗長なので削除できる a = 2 return a # ここでまた SCCP するともっと簡潔になる return 2 ``` 注意しないといけないのは、関数呼び出しは安易に削除できないということです。呼び出しには副作用(IO, グローバル変数への書き込み, etc)が伴うため、削除しても良いのか何かしらの方法で検証する必要があります。あまり簡単ではないので、実装する時は、まずは非常に限られたケースのみに対応させると良いでしょう。 ```py # DCE 前 a = add(1, 2); puts("hello world"); # DCE 後 a = add(1, 2); # 消していいのか? puts("hello world"); # 消せなさそう ``` ```py # 引数やローカル変数、足し算しか使っていない→副作用なさそう int add(int x, int y) { return x + y; } # なら消せそう # a = add(1, 2); ``` 参考: [LLVMでの実装](https://github.com/llvm/llvm-project/blob/main/llvm/lib/Transforms/Scalar/DCE.cpp), [`isInstructionTriviallyDead()`](https://github.com/llvm/llvm-project/blob/3198364e6e4943512ed48f2a1c1ab4c418b72f42/llvm/lib/Transforms/Utils/Local.cpp#L395) ## Peephole Peephole 最適化(のぞき穴的最適化)とは、命令列の一部分に対して行われるなんらかの最適化の総称です。 例えば、以下のような変換を行います。(ここでは適当なアセンブリを例に考えます) ```asm # Peephole 前 mov rax, 1 push rax pop rax # Peephole 後 mov rax, 1 ``` WIP :( https://ja.wikipedia.org/wiki/%E3%81%AE%E3%81%9E%E3%81%8D%E7%A9%B4%E7%9A%84%E6%9C%80%E9%81%A9%E5%8C%96 ## Inline https://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%B3%E3%83%A9%E3%82%A4%E3%83%B3%E5%B1%95%E9%96%8B ## Unroll https://ja.wikipedia.org/wiki/%E3%83%AB%E3%83%BC%E3%83%97%E5%B1%95%E9%96%8B ## CSE (Common Subexpression Elimination) https://ja.wikipedia.org/wiki/%E5%85%B1%E9%80%9A%E9%83%A8%E5%88%86%E5%BC%8F%E9%99%A4%E5%8E%BB ## Code Motion https://en.wikipedia.org/wiki/Code_motion (英語) > **code motion**, also known as code hoisting, code sinking, loop-invariant code motion, or code factoring, is **a blanket term for any process that moves code within a program for performance or size benefits** 参考: [LLVM LICM](https://github.com/llvm/llvm-project/blob/main/llvm/lib/Transforms/Scalar/LICM.cpp) ## Vectorize https://en.wikipedia.org/wiki/Automatic_vectorization (英語) *自作コンパイラに実装するとしても、優先度は低くなるでしょう* # コンパイラ最適化に適した、プログラムの形式 コンパイラ最適化のさまざまな(変形)手法を実装するためには、多くの場合、まずはプログラムを解析しなければなりません。 解析には色々な種類があり、ここまでで登場したデータフロー解析や、基本ブロックの支配木の構成、Scalar Evolution の解析などちょっと難しいものも存在します。 ここでは、データフロー解析の観点から見て扱いやすい、プログラムの形式を紹介します。 それが **SSA (Static Single Assignment, 静的単一代入)** 形式です。 ## SSA (Static Single Assignment) form > 静的単一代入形式、または SSA 形式(static single assignment form)とは、 > プログラムの表現形式の1つで、そのプログラム上のすべての変数の使用に対して、 > その使用に対応する定義は1ヶ所しかないように表現したものである。 > これは、変数の値の定義と使用の関係を明確に表現する形式であり、 > 従来のデータの流れの解析とは違う方法が、この形式を使うことによって可能になる。 > > 引用元:[コンパイラの構成と最適化](https://www.asakura.co.jp/detail.php?book_code=12177), p.334 ... ## なぜ SSA はコンパイラ最適化に適しているか SSA 形式が、コンパイラ最適化において一番優れているというわけではありません。 ただ、世の中の多くのコンパイラやコンパイラ基盤ライブラリ(e.g. [LLVM](https://releases.llvm.org/13.0.0/docs/LangRef.html#abstract), [GCC](https://gcc.gnu.org/onlinedocs/gccint/SSA.html), [Cranelift](https://github.com/bytecodealliance/wasmtime/blob/main/cranelift/docs/ir.md), [COINS](http://coins-compiler.osdn.jp/COINSdoc/summary/summary.html), etc)は SSA 形式を(内部で)採用しており、これは SSA 形式が重要な役割を果たすことを裏付けています。 > なぜ、中間言語では SSA を使うとよいのでしょうか。それは、SSAを利用すると、実行コードの最適化(オプティマイズ)が行いやすくなるからです。(中略)変数を SSA で管理すると、一度変数に代入された値が変化しないことが保障されるため、処理と変数の関連性が追求しやすくなります。 > ―― 出村成和「LLVM / Clang 実践活用ハンドブック」p.62 ... ## SSAが実世界で使われている例: LLVM IR https://godbolt.org/z/3YfYM4vEP https://releases.llvm.org/14.0.0/docs/LangRef.html ... ## SSAが実世界で使われている例: Cranelift IR https://github.com/bytecodealliance/wasmtime/blob/main/cranelift/docs/ir.md ... # コンパイラ最適化の具体的な実装方法 ## 普通のプログラム→SSA 変換 支配木、支配辺境、$\phi$関数... ## 8つの最適化 ### Constant Fold ### DCE (Dead Code Elimination) ### Peephole ### Inline ### Unroll ### CSE (Common Subexpression Elimination) ### Code Motion ### Vectorize

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully