📜  编译器设计中的代码优化

📅  最后修改于: 2021-09-28 09:57:29             🧑  作者: Mango

合成阶段的代码优化是一种程序转换技术,它试图通过减少中间代码消耗的资源(即 CPU、内存)来改进中间代码,从而产生更快运行的机器代码。编译器优化过程应满足以下目标:

  • 优化必须是正确的,不能以任何方式改变程序的含义。
  • 优化应该提高程序的速度和性能。
  • 编译时间必须保持合理。
  • 优化过程不应延迟整个编译过程。

什么时候优化?
代码的优化通常在开发阶段结束时执行,因为它会降低可读性并添加用于提高性能的代码。

为什么要优化?
优化算法超出了代码优化阶段的范围。所以程序被优化了。它可能涉及减少代码的大小。因此优化有助于:

  • 减少占用的空间,提高编译速度。
  • 手动分析数据集需要大量时间。因此,我们使用 Tableau 等软件进行数据分析。同样,手动执行优化也很乏味,最好使用代码优化器来完成。
  • 优化的代码通常会促进可重用性。

代码优化的类型 –优化过程可以大致分为两种类型:

  1. 机器独立优化——这个代码优化阶段试图改进中间代码以获得更好的目标代码作为输出。这里转换的中间代码部分不涉及任何CPU寄存器或绝对内存位置。
  2. 机器相关优化——机器相关优化是在目标代码生成之后以及代码根据目标机器架构进行转换时进行的。它涉及 CPU 寄存器,并且可能具有绝对内存引用而不是相对引用。依赖于机器的优化器努力最大限度地利用内存层次结构。

代码优化通过以下不同方式完成:

  1. 编译时间评估:
    (i)  A = 2*(22.0/7.0)*r 
         Perform 2*(22.0/7.0)*r at compile time.
    (ii)  x = 12.4
          y = x/2.3 
          Evaluate x/2.3 as 12.4/2.3 at compile time.
    
  2. 变量传播:
    //Before Optimization 
    c = a * b                                               
    x = a                                                  
    till                                                           
    d = x * b + 4 
     
     
    //After Optimization 
    c = a * b  
    x = a
    till
    d = a * b + 4
    

    因此,在变量传播之后,a*b 和 x*b 将被识别为公共子表达式。

  3. 死代码消除:变量传播经常导致赋值语句变成死代码
    c = a * b                                                
    x = a                                                
    till                                                          
    d = a * b + 4   
     
    //After elimination :
    c = a * b
    till
    d = a * b + 4
    
  4. 代码运动:
    • 降低表达式的求值频率。
    • 将循环不变语句带出循环。
    a = 200;
     while(a>0)
     {
         b = x + y;
         if (a % b == 0}
         printf(“%d”, a);
       }
     
     
    //This code can be further optimized as
    a = 200;
    b = x + y;
    while(a>0)
     {
         if (a % b == 0}
         printf(“%d”, a);
       }
    
  5. 感应变量和强度降低:
    • 归纳变量在循环中用于以下类型的赋值 i = i + 常量。
    • 强度降低意味着用低强度代替高强度运算符。
    i = 1;                                                                      
    while (i<10)                                                          
    {                                                                             
        y = i * 4; 
    }
      
      
    //After Reduction
    i = 1
    t = 4
    { 
       while( t<40) 
       y = t; 
       t = t + 4;
    }
    

在哪里应用优化?
现在我们了解了优化的必要性及其两种类型,现在让我们看看在哪里应用这些优化。

  • 源程序
    优化源程序涉及更改算法或更改循环结构。用户是这里的参与者。
  • 中间代码
    优化中间代码涉及更改地址计算和转换涉及的过程调用。这里编译器是演员。
  • 目标代码
    优化目标代码由编译器完成。寄存器的使用、选择和移动指令是目标代码中涉及的优化的一部分。
    优化阶段
    通常有两个优化阶段:
  • 全局优化:
    转换应用于包含函数、过程和循环的大型程序段。
  • 局部优化:
    转换应用于小块语句。局部优化在全局优化之前完成。

参考 – https://en.wikipedia.org/wiki/Optimizing_compiler