📜  编译器设计中的恒定传播

📅  最后修改于: 2021-09-27 14:52:30             🧑  作者: Mango

恒定传播是编译器设计中的局部代码优化技术之一。它可以定义为替换表达式中变量的常量值的过程。简而言之,我们可以说,如果某个值被分配了一个已知常量,那么我们可以简单地用常量替换该值。分配给变量的常量可以通过流图传播,并且可以在使用变量时替换。

常量传播是利用编译器中的到达定义分析结果来执行的,这意味着如果所有变量的到达定义都具有相同的赋值,即为该变量分配相同的常量,则该变量具有常量值,并且可以被该常量替换。

假设我们使用 pi 变量并将其赋值为 22/7

pi = 22/7 = 3.14

在上面的代码中,编译器必须首先执行除法运算,这是一个代价高昂的运算,然后将计算结果 3.14 赋给变量 pi。现在,如果我们必须随时使用 pi 的这个常量值,那么编译器必须再次查找该值并再次执行除法运算,然后将其分配给 pi 并使用它。当我们可以直接将值 3.14 分配给 pi 变量时,这不是一个好主意,从而减少代码运行所需的时间。

此外,常量传播减少了将值从一个位置或变量直接复制到另一个位置或变量的情况的数量,以便将它们的值简单地分配给另一个变量。例如:

考虑以下伪代码:

a = 30
b = 20 - a /2
c = b * ( 30 / a + 2 ) -  a

我们可以看到,在 a 的第一个表达式值中分配了一个常量值,即 30。现在,当编译器开始执行第二个表达式时,它遇到了 a,因此它会向上查找第一个表达式以查找 a 的值然后再次将 30 的值赋给 a,然后执行第二个表达式。现在到了第三个表达式,再次遇到 b 和 a,然后它需要再次计算第一个和第二个表达式以计算 c 的值。因此,a 需要传播 3 次。这个过程非常耗时。

我们可以改为重写与以下相同的代码:

a = 30
b = 20 - 30/2
c = b * ( 30 / 30 + 2) - 30

与先前的代码相比,此更新的代码更快,因为编译器不需要一次又一次地返回到先前的表达式以查找和复制变量的值来计算当前表达式。这可以节省大量时间,从而降低时间复杂度并更有效地执行操作。

请注意,这种常量传播技术行为取决于编译器,就像很少有编译器在基本块内执行常量传播操作一样;而一些编译器在更复杂的控制流中执行常量传播操作。