📜  基本块的优化

📅  最后修改于: 2022-05-13 01:55:52.433000             🧑  作者: Mango

基本块的优化

在编译器的中间代码生成阶段之后,对基本块进行优化。优化是转换程序的过程,通过消耗更少的资源和提供高速来改进代码。在优化中,高级代码被它们等效的高效低级代码所取代。基本块的优化可以与机器相关或与机器无关。

有两种类型的基本块优化:

  1. 结构保持转换
  2. 代数变换

基本块优化

结构保持转换:

基本块的结构保持变换包括:

  1. 死代码消除
  2. 公共子表达式消除
  3. 重命名临时变量
  4. 两个独立相邻语句的交换

死代码消除:

死代码被定义为在程序执行期间从不执行的那部分代码。因此,为了优化,消除了这样的代码或死代码。在程序期间从不执行的代码(死代码)需要时间,因此为了优化和速度,将其从代码中消除。消除死代码会提高程序的速度,因为编译器不必翻译死代码。

例子:

// Program with Dead code
int main()
{
    x = 2 
    if (x > 2) 
      cout << "code"; // Dead code
    else 
      cout << "Optimization";
    return 0;
}
// Optimized Program without dead code
int main()
{
    x = 2;
    cout << "Optimization"; // Dead Code Eliminated
    return 0;
}

通用子表达式消除:

在这种技术中,经常使用的常用子表达式只计算一次,并在需要时重复使用。 DAG(有向无环图)用于消除常见的子表达式。

例子:

临时变量的重命名:

包含临时变量实例的语句可以更改为新临时变量的实例,而无需更改基本块值。

示例:语句 t = a + b 可以更改为 x = a + b,其中 t 是临时变量,x 是新的临时变量,而不更改基本块的值。

两个独立相邻语句的交换:

如果一个块有两个相邻的独立语句可以互换而不影响基本块值。

例子:

t1 = a + b
t2 = c + d 

块的这两个独立的语句可以互换而不影响块的值。

代数变换:

基本块的代数变换包括:

  1. 恒定折叠
  2. 复制传播
  3. 强度降低

1. 恒定折叠:

求解连续的常数项,这样编译器就不需要求解这个表达式。

例子:

x = 2 * 3 + y   ⇒ x = 6 + y  (Optimized code)

2.复制传播:

它有两种类型,可变传播和恒定传播。

变量传播:

不断传播:

3.强度降低:

用更便宜的语句/指令替换昂贵的语句/指令。

x = 2 * y (costly)  ⇒  x = y + y (cheaper)
x = 2 * y (costly)  ⇒ x = y << 1 (cheaper)

循环优化:

循环优化包括以下策略:

  1. 代码运动和频率降低
  2. 感应变量消除
  3. 循环合并/组合
  4. 循环展开

1.代码运动和频率降低

将循环不变代码移到循环之外。

// Program with loop variant inside loop
int main()
{
    for (i = 0; i < n; i++) {
        x = 10;
        y = y + i;
    }
    return 0;
}
// Program with loop variant outside loop
int main()
{
    x = 10;
    for (i = 0; i < n; i++)
        y = y + i;
    return 0;
}

2.归纳变量消除:

消除循环中使用的各种不必要的归纳变量。

// Program with multiple induction variables
int main()
{
    i1 = 0;
    i2 = 0;
    for (i = 0; i < n; i++) {
        A[i1++] = B[i2++];
    }
    return 0;
}
// Program with one induction variable
int main()
{
    for (i = 0; i < n; i++) {
        A[i++] = B[i++]; // Only one induction variable
    }
    return 0;
}

3.循环合并/组合:

如果执行的操作可以在单个循环中完成,则合并或组合循环。

// Program with multiple loops
int main()
{
    for (i = 0; i < n; i++)
        A[i] = i + 1;
    for (j = 0; j < n; j++)
        B[j] = j - 1;
}
return 0;
}  
// Program with one loop when multiple loops are merged
int main()
{
    for (i = 0; i < n; i++) {
        A[i] = i + 1;
        B[i] = i - 1;
    }
    return 0;
}

4.循环展开:

如果存在可以减少循环执行次数的简单代码,则可以用这些代码替换循环。

// Program with loops
int main()
{
    for (i = 0; i < 3; i++)
        cout << "Cd";
    return 0;
}
// Program with simple code without loops
int main()
{
    cout << "Cd";
    cout << "Cd";
    cout << "Cd";
    return 0;
}