Go 編譯器技術死碼消消樂

一、前言

死代碼消除( dead code elimination, 縮寫 DCE )是用來移除對程序執行結果沒有任何影響的代碼,以此 減少程序的體積大小 ,並且還可以避免程序在執行過程中進行一些不必要的運算行爲,從而 減少執行時間 。

需要注意的是,除了不會執行到的代碼( unreachable code ),一些只會影響到無關程序執行結果的變量( dead variables ),也屬於死碼( dead code )的範疇。

二、舉例說明

import "fmt"
func max(a, b int) int {
  if a > b {
    return a
  }
  return b
}
const a, b = 10, 20
func main() {
  if max(a, b) == a {
    fmt.Println(a)
  }
}

執行 go build 構建:

修改代碼:

const a, b = 10, 20

把如上代碼變更爲如下代碼:

執行 go build 構建:

對比之前,發現 const 變更爲 var 之後,編譯的文件大小變大了,爲什麼?

2.1 爲什麼編譯的文件變大?

首先編譯器會對 max 函數進行內聯優化, const.go 優化後如下:

package main
import "fmt"
const a, b = 10, 20
func main() {
  var result int
  if a > b {
    result = a
  } else {
    result = b
  }
  if result == a {
    fmt.Println(a)
  }
}

對於常量 a 和 b ,編譯器在編譯時可以判斷出 a 永遠是大於 b 的,即 a > b 永遠爲 false ,也就是說 if {} 分支屬於 unreachable code 將永遠不會被執行,所以編譯器會進行第一次優化:分支消除

package main
import "fmt"
const a, b = 10, 20
func main() {
  var result int
  result = b
  if result == a {
    fmt.Println(a)
  }
}

由於 result 變量後續沒有再被引用,所以 result 實際也是一個常量。相同道理,result == a 永遠爲 false ,編譯器會進行第二次分支消除優化:

package main
import "fmt"
const a, b = 10, 20
func main() {
  var result int
  result = b
}

對於剩下的常量則明顯屬於 dead variables ,再次優化:

package main
func main() {
}

而對於 var 定義變量, 參數爲 全局變量 不爲常量, 編譯器並不知道運行過程中 x、y 會不會發生改變, 因此不能進行死代碼消除.

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/UhwHeULIHf52xf0PMudR7Q