<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SSA:終于知道 Go 編譯器偷摸做了哪些事

          共 2047字,需瀏覽 5分鐘

           ·

          2022-01-01 17:46


          在go的源碼和匯編碼之間,其實(shí)編譯器在你眼皮底下偷偷又做了不少事情,而ssa就是查看查看編譯器優(yōu)化行為的利器。

          在golang中,我們可以使用go tool compile -S main.go 工具將一個go程序直接轉(zhuǎn)換為匯編代碼。但是你會發(fā)現(xiàn),最終編譯出來的匯編代碼其實(shí)是已經(jīng)被優(yōu)化過了的,編譯器其實(shí)很聰明,甚至將一些函數(shù)合并,取消等。至于這個過程,并不是一蹴而就的,在golang代碼和最終的匯編代碼中,還有一種中間的代碼結(jié)構(gòu),這個結(jié)構(gòu)就叫做SSA (Static Single Assignment) 靜態(tài)單賦值。

          這個中間的代碼結(jié)構(gòu)是有必要存在的,go源碼解析后是一個AST樹,是一個樹形結(jié)構(gòu),而最終的匯編是一條一條的線性命令。將樹形結(jié)構(gòu)轉(zhuǎn)化拆分優(yōu)化為匯編命令是比較復(fù)雜的。所以這里將這么一個大的步驟分成兩步走,能大大降低編譯器優(yōu)化的難度。

          怎么生成ssa

          我們可以使用命令 GOSSAFUNC=Foo go build index.go ?來看我們將一個go源碼,怎么轉(zhuǎn)化為SSA的全過程的。

          go代碼

          package?array


          func?Foo?()?int?{
          ?a?:=?[3]int{1,3,5}
          ?i?:=?2
          ?elem?:=?a[i]
          ?return?elem
          }

          image-20211218225223395

          生成ssa.html

          怎么看ssa

          image-20211218225244800

          這個html中的ssa中間語言的語法是由 cmd/compile/internal/ssa/gen/genericOps.go 生成的。

          image-20211218230201931

          每一行和對應(yīng)的SSA代碼都標(biāo)記出來了,有一些即使沒有SSA的經(jīng)驗(yàn),也是能立馬看懂的。比如像v10 是常量1,而v13是代表指針指向a[0], v14 代表將常量1存儲進(jìn)入a[0]。不過有一些則不是那么容易看出了。

          通過中間可以看出過了很多優(yōu)化步驟才最終生成了匯編碼。

          image-20211218230740078

          有哪些步驟可以參考這里:https://github.com/golang/go/blob/release-branch.go1.15/src/cmd/compile/internal/ssa/compile.go#L418

          至于每個步驟做了什么事情,這個就很復(fù)雜了。

          關(guān)于ssa

          關(guān)于ssa,我自己的理解就是,將源碼的AST樹,先演變成像

          v1=?xxx
          v2=?xxx
          v3=?xxx

          這種線性執(zhí)行語句。這種語句的特點(diǎn)就是每一行都定義了一個變量。所以叫“靜態(tài)單賦值語句”。然后使用各種之間的賦值規(guī)則,可以很容易看出哪些賦值變量其實(shí)是沒有用到的。對于沒有用到的直接可以刪除。當(dāng)然還有其他各種規(guī)則,最終將v1...vn的賦值變量進(jìn)行預(yù)計算,優(yōu)化,最后優(yōu)化為最簡的幾個賦值變量。這點(diǎn)可以從ssa.html的start到最后的trim就看出了。

          最開始的源碼

          image-20211218231704579

          切換為AST樹

          image-20211218231717903

          再變成SSA語言

          image-20211218231608947

          經(jīng)過不斷優(yōu)化,變成三個執(zhí)行語言。(其實(shí)這個foo函數(shù)直接可以在編譯階段將5返回)

          image-20211218231647243

          最后再變化為匯編碼:


          這個編譯器優(yōu)化的過程,我感覺對于語言使用者還是主要適用于純研究。

          比如想研究下數(shù)組是在棧上分配內(nèi)存還是在靜態(tài)數(shù)據(jù)區(qū)分配內(nèi)存,可以生成ssa看看。

          或者想研究下哪行代碼對應(yīng)哪個內(nèi)部函數(shù)等。

          參考:

          https://gocompiler.shizhz.me/10.-golang-bian-yi-qi-han-shu-bian-yi-ji-dao-chu/10.2.1-ssa

          https://oftime.net/2021/02/14/ssa/

          https://draveness.me/golang/docs/part1-prerequisite/ch02-compile/golang-ir-ssa/

          https://github.com/golang/go/blob/master/src/cmd/compile/internal/ssa/README.md

          https://en.wikipedia.org/wiki/Static_single_assignment_form



          推薦閱讀


          福利

          我為大家整理了一份從入門到進(jìn)階的Go學(xué)習(xí)資料禮包,包含學(xué)習(xí)建議:入門看什么,進(jìn)階看什么。關(guān)注公眾號 「polarisxu」,回復(fù)?ebook?獲?。贿€可以回復(fù)「進(jìn)群」,和數(shù)萬 Gopher 交流學(xué)習(xí)。

          瀏覽 158
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产精品久久久久久高潮 | 快撸视频| 午夜在线成人视频 | 成人性生活片 | 激情五月天丁香 |