Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

常量折叠与常量传播

复习

  • 优化为什么必须保留行为:等价是前提
  • 数据流分析:判断某点的值是否为常量
  • 三地址码:优化作用的中间表示

TL;DR

  • 常量折叠:编译时把常量运算直接算出来
  • 常量传播:把“其实是常量”的变量替换成常量
  • 两者常配合使用,能省掉大量运行时的计算
  • 前提是能确定它一定是常量

正文

  优化里最直观的一类,是处理“常量”。既然编译时就知道结果,何必留到运行时再算?这有两个动作:常量折叠常量传播

常量折叠:能算的先算掉

  常量折叠(constant folding)很直白:如果一个运算的操作数都是编译时已知的常量,那就直接把它算出来,把运算替换成结果。

x = 2 + 3        →        x = 5

  反正结果固定,运行时就别再算 2 + 3 了。这不需要任何分析,只要看到常量运算就能折叠。

常量传播:把常量传出去

  常量传播(constant propagation)更进一步:如果某个变量在某处一定是常量,就把用到它的地方替换成那个常量。

x = 5
y = x + 1       →        y = 6

  因为 x 确定是 5,x + 1 就确定是 6,于是它也能被折叠。常量传播把“常量”从一个地方,扩散到了它被使用的地方,从而制造出更多可折叠的机会。

前提:得确定“它一定是”

  这里有个关键前提:必须确认这个变量在那一点上“一定是常量”。

  如果 x 在别处可能被改过,或者来自一个不确定的输入,那就不能传。判断“某点上变量是否一定是常量”,正是数据流分析的活儿——它沿着控制流,看 x 的值在所有可能路径上是否都只有一个确定的值。

  所以你看,优化不是拍脑袋,而是建立在分析之上的。 折叠和传播这对搭档,常常是优化的第一步:把常量算掉之后,往往会暴露出更多可优化的空间。

思考题 1

  常量折叠和常量传播,分别做什么?

思考题 2

  常量传播为什么需要先确认“它一定是常量”?

小结

知识点

  • 常量折叠把常量运算在编译期算掉
  • 常量传播把确定是常量的变量替换为常量
  • 两者配合能触发更多折叠
  • “一定是常量”由数据流分析判定

参考资料

  1. Wikipedia(zh):常量折叠:在编译期计算常量表达式
  2. Wikipedia(zh):常量传播:把常量值传播到使用处

思考题答案(仅供参考)

思考题 1

  常量折叠把操作数都是常量的运算在编译期直接算出结果,例如 2+3 变成 5;常量传播则判断某个变量在某点一定是常量,把使用它的地方替换成该常量,例如把 x+1 换成 6

思考题 2

  因为只有当该变量在那一点确定是常量时,替换才不改变程序行为。如果它在别处可能被修改,或来自不确定的输入,替换就会算错。因此需要数据流分析来确认“所有路径上它都是同一个确定值”。

协议

  本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

封面图

设计师 | 南国微雪